POJ - 3683 Priest John's Busiest Day (2-SAT)

题意:有N个婚礼,每个婚礼可以在两段时间内举行,要求N段婚礼的时间没有相交,可行则输出方案
分析:2-SAT求解.建图就是若婚礼i的第一段时间与婚礼j的第一段时间相交则选i1则必选j2,以此类推.
Tarjan跑出强联通分量之后,反向缩点建边并染色,最后输出可行解
2-SAT输出方案可作为模板,其思路参考博客:https://blog.csdn.net/Hawo11/article/details/74908233

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
typedef long long LL;
const int maxn = 1e5+10;
const int MAXM = 2e6+5;
struct Edge{
    int v,next;
}edges[MAXM],E[MAXM];
int head[maxn],tot;
int H[maxn],tt;
stack<int> S;
int pre[maxn],low[maxn],sccno[maxn],dfn,scc_cnt,ind[maxn],col[maxn];
void init()
{
    tt = tot = dfn = scc_cnt=0;
    memset(H,-1,sizeof(H));
    memset(pre,0,sizeof(pre));
    memset(sccno,0,sizeof(sccno));
    memset(head,-1,sizeof(head));
    memset(ind,0,sizeof(ind));
}
void AddEdge(int u,int v)   {
    edges[tot] = (Edge){v,head[u]};
    head[u] = tot++;
}

void nAddEdge(int u,int v){
    E[tt] = (Edge){v,H[u]};
    H[u] = tt++;
}

void Tarjan(int u)
{
    int v;
    pre[u]=low[u]=++dfn;
    S.push(u);
    for(int i=head[u];~i;i=edges[i].next){
        v= edges[i].v;
        if(!pre[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!sccno[v]){
            low[u]=min(low[u],pre[v]);
        }
    }
    if(pre[u]==low[u]){
        int x;
        ++scc_cnt;
        for(;;){
            x = S.top();S.pop();
            sccno[x]=scc_cnt;
            if(x==u)break;
        }
    }
}

int con[maxn];


struct Node{
    int st,ed;
}p[2005];
int N,all;
#include<queue>
void solve()
{
    int a,b;
    for(int i=0;i<all;++i){
        if(!pre[i]) Tarjan(i);
    }
    for(int i=0;i<all;i+=2){
        if(sccno[i]==sccno[i^1]){
            printf("NO\n");
            return;
        }
        a = sccno[i], b = sccno[i^1];
        con[a] = b;
        con[b] = a;
    }
    printf("YES\n");
    //缩点
    for(int u=0;u<all;++u){
        a = sccno[u];
        for(int i = head[u];~i;i=edges[i].next){
            int v = edges[i].v;
            b = sccno[v];
            if(a!=b){
                nAddEdge(b,a);
                ind[a]++;
            }
        }
    }
    //逆拓扑排xu
    queue<int> Q;
    memset(col,0,sizeof(col));
    for(int i=1;i<=scc_cnt;++i){
        if(!ind[i]) Q.push(i);
    }
    while(!Q.empty()){
        int u  =Q.front(); Q.pop();
        if(!col[u]){
            col[u] = 1;
            col[con[u]] = 2;
        }
        for(int i=H[u];~i;i=E[i].next){
            int v = E[i].v;
            ind[v]--;
            if(!ind[v]){
                Q.push(v);
            }
        }
    }

    int h1,m1,h2,m2;
    for(int i=0;i<all;i+=2){
        int pt;
        if(col[sccno[i]]== 1) pt = i;
        else pt = i^1;
        h1 = p[pt].st/60,m1 =p[pt].st %60;
        h2 = p[pt].ed/60,m2 =p[pt].ed %60;
        printf("%02d:%02d %02d:%02d\n",h1,m1,h2,m2);
    }
}

bool check(int i,int j)
{
    if(p[i].ed<=p[j].st || p[j].ed<=p[i].st) return true;
    else return false;
}

char op[50];
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int h1,m1,h2,m2,len;
    while(scanf("%d",&N)==1){
        init();
        all = 2*N;
        bool flag = true;
        for(int i=0;i<all;i+=2){
            scanf("%d:%d %d:%d %d",&h1,&m1,&h2,&m2,&len);
            p[i].st = h1*60+m1;
            p[i].ed = p[i].st + len;
            p[i^1].st = h2*60+m2-len;
            p[i^1].ed = p[i^1].st +len;
            if(p[i^1].ed - p[i].st<len) flag = false;
        }

        if(!flag){
            printf("NO\n");
            continue;
        }

        int a1,a2,b1,b2;
        //[1-2N] 为去 ,[2N+1,4N]为不去
        for(int i=0;i<all;i+=2){
            a1 = i; a2 = i^1;
            for(int j= i+2 ;j< all ; j+=2){
                b1 = j, b2 =j^1;
                if(!check(a1,b1)){
                    AddEdge(a1,b2);
                    AddEdge(b1,a2);
                }
                if(!check(a1,b2)){
                    AddEdge(a1,b1);
                    AddEdge(b2,a2);
                }
                if(!check(a2,b1)){
                    AddEdge(a2,b2);
                    AddEdge(b1,a1);
                }
                if(!check(a2,b2)){
                    AddEdge(a2,b1);
                    AddEdge(b2,a1);
                }
            }
        }
        solve();
    }
    return 0;
}

posted @ 2018-09-07 18:55  xiuwenL  阅读(120)  评论(0编辑  收藏  举报