【算法练习】POJ - 3683 Priest John's Busiest Day (2-SAT)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengwill97/article/details/82056098

题意

有一个小镇上只有一个牧师。这个小镇上有一个传说,在九月一日结婚的人会受到爱神的保佑,但是要牧师举办一个仪式。这个仪式要么在婚礼刚刚开始的时候举行,要么举行完婚礼正好结束。
现在已知有n场婚礼,告诉你每一场的开始和结束时间,以及举行仪式所需要的时间。问牧师能否参加所有的婚礼,如果能则输出一种方案。

题解

2-SAT + 路径输出
首先建图不难,判断两个时间段是否相交。
然后按照tarjan缩点,跑一边逆拓扑排序,按照逆序的结果开始选择,并把它的对称点删掉。求出来的就是结果。
逆拓扑排序直接把缩点后的图边反向建立,然后跑一边正的拓扑排序就好了。
注意输出的时候要按照原来婚礼的顺序进行输出。

代码

#include<cstdio>
#include<queue>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int tot, head[10005], nhead[10005], tot2;
int n;
struct edge{
    int to, nxt;
}e[nmax<<1], ng[nmax<<1];
void add_edge(int u, int v) {
    e[tot].to = v;
    e[tot].nxt = head[u];
    head[u] = tot++;
}
void add_edge2(int u, int v) {
    ng[tot2].to = v;
    ng[tot2].nxt = nhead[u];
    nhead[u] = tot2++;
}
struct Node{
    int st1, st2, last;
}node[10005];
int dfn[10005], low[10005], ss[10005], st, scc_cnt, color[10005], in[10005], dfs_clock;
int belong[10005], oppcolor[10005];
bool instack[10005], ban[10005];
vector<int> scc[10005];
queue<int> q;
void init() {
    tot2 = scc_cnt = st = dfs_clock = tot = 0 ;
    while(!q.empty()) q.pop();
    memset(head, -1, sizeof head);
    memset(nhead, -1, sizeof nhead);
    memset(dfn, 0, sizeof dfn);
    memset(low, 0, sizeof low);
    memset(color, 0, sizeof color);
    memset(ban, 0 ,sizeof ban);
    memset(belong, 0, sizeof belong);
    memset(in, 0, sizeof in);
    memset(oppcolor, 0, sizeof oppcolor);
}
void tarjan(int u) {
    dfn[u] = low[u] = ++ dfs_clock;
    ss[st++] = u;
    instack[u] = true;
    for(int i = head[u]; i != -1; i = e[i].nxt) {
        int v = e[i].to;
        if(!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if(instack[v]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if(low[u] == dfn[u]) {
        scc_cnt++;
        scc[scc_cnt].clear();
        int tmp;
        while(1) {
            tmp = ss[--st];
            color[tmp] = scc_cnt;
            scc[scc_cnt].push_back(tmp);
            instack[tmp] = false;
            if(tmp == u)
                break;
        }
    }
}
void toposort(int u) {
    q.push(u);
    in[u] = -1;
    for(int i = nhead[u]; i != -1; i = ng[i].nxt) {
        int v = ng[i].to;
        in[v] --;
        if(!in[v])
            toposort(v);
    }
}
bool notcross(int as, int ae, int bs, int be) {
    if(be <= as || bs >= ae)
        return true;
    else
        return false;
}
void dfs(int u) {
    ban[u] = 2;
    for(int i = nhead[u]; i != -1; i = ng[i].nxt) {
        int v = ng[i].to;
        if(ban[v] == 0)
            dfs(v);
    }
}
void show(int hour, int minute) {
    if(hour < 10) printf("0%d:",hour);
    else printf("%d:",hour);
    if(minute < 10) printf("0%d",minute);
    else printf("%d",minute);
}
int main(){
    while(scanf("%d", &n) != EOF) {
        init();
        int sth, stm, edh, edm , last;
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &sth);
            getchar();
            scanf("%d %d", &stm, &edh);
            getchar();
            scanf("%d %d", &edm, &last);
            node[i].st1 = sth * 60 + stm;
            node[i].st2 = edh * 60 + edm - last;
            node[i].last = last;
        }
        for(int i = 1; i <= n; ++i) {
            for(int j = i + 1; j <= n; ++j) {
                if(!notcross(node[i].st1 , node[i].st1 + node[i].last, node[j].st1, node[j].st1 + node[j].last)) {
                    add_edge(i, j + n);
                    add_edge(j, i + n);
                }
                if(!notcross(node[i].st2 ,node[i].st2 + node[i].last, node[j].st1, node[j].st1 + node[j].last)) {
                    add_edge(i + n, j + n);
                    add_edge(j, i);
                }
                if(!notcross(node[i].st1, node[i].st1 + node[i].last, node[j].st2, node[j].st2 + node[j].last)) {
                    add_edge(i, j);
                    add_edge(j + n, i + n);
                }
                if(!notcross(node[i].st2, node[i].st2 + node[i].last, node[j].st2, node[j].st2+ node[j].last)) {
                    add_edge(i + n, j);
                    add_edge(j + n, i);
                }
            }
        }
        for(int i = 1; i <= 2* n; ++i) {
            if(!dfn[i]) {
                tarjan(i);
            }
        }
        bool isok = true;
        for(int i = 1; i <= n; ++i) {
            if(color[i] == color[i + n]) {
                isok = false;
                break;
            }
        }
        if(!isok) {
            printf("NO\n");
            continue;
        } else
            printf("YES\n");
        for(int u = 1; u <= 2 * n; ++u) {
            for(int i = head[u]; i != -1; i = e[i].nxt) {
                int v = e[i].to;
                if(color[u] != color[v]) {
                    add_edge2(color[v], color[u]);
                    in[color[u]] ++;
                }
            }
            if(u <= n) oppcolor[color[u]] = color[u + n];
            else oppcolor[color[u]] = color[u - n];
        }
        for(int i = 1; i <= scc_cnt; ++i) {
            if(!in[i])
                toposort(i);
        }
        for(int j = 1; j <= scc_cnt; ++j){
            int now = q.front();
            q.pop();
            if(ban[now] == 0) {
                ban[now] = 1;
                ban[oppcolor[now]] = 2;
                for(int i = 0; i < scc[now].size(); ++i) {
                    belong[scc[now][i]] = 1;
                }
            }
        }
        for(int i = 1; i <= n; ++i) {
            if(belong[i] == 1) {
                show(node[i].st1 / 60 , node[i].st1 % 60);
                printf(" ");
                show( (node[i].st1 + node[i].last) / 60, (node[i].st1 + node[i].last) % 60);
                printf("\n");
            } else {
                show(node[i].st2 / 60 , node[i].st2 % 60);
                printf(" ");
                show( (node[i].st2 + node[i].last) / 60, (node[i].st2 + node[i].last) % 60);
                printf("\n");
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pengwill97/article/details/82056098
今日推荐