POJ 3683 2-sat

来源:互联网 发布:crt结束tomcat端口 编辑:程序博客网 时间:2024/05/22 14:56

题目链接:http://poj.org/problem?id=3683
题意:每个婚礼有两个时段(婚礼开始,或者结束)可以进行特别仪式,特别仪式必须要有神父在场,神父只有一个,问是否能满足所有婚礼的需求。
规模:( 1 ≤ N ≤ 1000),N场婚礼
类型: 2-sat
分析:这是“大白书”上的2-sat基础。
每场婚礼都只有两个时间段,而且不能冲突,是2-sat的典型模型。
我们将所有不能共存的关系列出,据此建边,跑2-sat就行了。
这里稍微解释一下建边过程:

对于两场婚礼a,b用a表示“婚礼开始时举行仪式”,用(!a)表示“婚礼结束时举行仪式”,b同a;那么我们有四种组合方式:(a,b),(a,!b),(!a,b),(!a,!b)对于每组确定的a,b,我们可以得到这四种组合是否成立。因为求的是2-sat,我们只需要对冲突的组合建边:

这里写图片描述

时间复杂度&&优化:
代码:

#include <iostream>#include <algorithm>#include <stdio.h>#include <stdlib.h>#include <cstring>using namespace std;const int MAXN=2005;const int MAXM=40000000;int n;struct Time{    int s,t;    int l;}time[MAXN];struct Edge{    int to,next;}edge[MAXM];int head[MAXN],tot;void init(){    tot=0;    memset(head,-1,sizeof(head));}void add_edge(int u,int v){    edge[tot].to=v;edge[tot].next=head[u];head[u]=tot++;}void ADD(int i,int j){    Time a=time[i];    Time b=time[j];    if(min(a.s+a.l,b.s+b.l)>max(a.s,b.s)){        //a=>!b,b=>!a        add_edge((2*i),(2*j)^1);        add_edge((2*j),(2*i)^1);    }    if(min(a.s+a.l,b.t)>max(a.s,b.t-b.l)){//cout<<2;        add_edge((2*i),2*j);        add_edge((2*j)^1,(2*i)^1);    }    if(min(a.t,b.s+b.l)>max(a.t-a.l,b.s)){//cout<<3;        add_edge((2*i)^1,(2*j)^1);        add_edge(2*j,2*i);    }    if(min(a.t,b.t)>max(a.t-a.l,b.t-b.l)){//cout<<4;        add_edge((2*i)^1,2*j);        add_edge((2*j)^1,2*i);    }}bool vis[MAXN];int S[MAXN],top;bool dfs(int u){    if(vis[u^1])return false;    if(vis[u])return true;    vis[u]=true;    S[top++]=u;    for(int i=head[u];i!=-1;i=edge[i].next){        if(!dfs(edge[i].to))            return false;    }    return true;}bool Twosat(int n){    memset(vis,false,sizeof(vis));    for(int i=0;i<n;i+=2){        if(vis[i]||vis[i^1])continue;        top=0;        if(!dfs(i)){            while(top)vis[S[--top]]=false;            if(!dfs(i^1))return false;        }    }    return true;}void solve(){    if(Twosat(2*n)){        printf("YES\n");        for(int i = 0;i < n;i++)            if(vis[i*2]){                printf("%02d:%02d %02d:%02d\n",time[i].s/60,time[i].s%60,(time[i].s+time[i].l)/60,(time[i].s+time[i].l)%60);            }            else{                printf("%02d:%02d %02d:%02d\n",(time[i].t-time[i].l)/60,(time[i].t-time[i].l)%60,time[i].t/60,time[i].t%60);            }        return;    }    printf("NO\n");}int main(){    while(scanf("%d",&n)==1){        init();        for(int i=0;i<n;i++){            int a,b,c;            scanf("%d:%d",&a,&b);            time[i].s=a*60+b;            scanf("%d:%d",&a,&b);            time[i].t=a*60+b;            scanf("%d",&time[i].l);        }        for(int i=0;i<n;i++){            for(int j=i+1;j<n;j++){                ADD(i,j);            }        }//        for(int i=0;i<2*n;i++){//            cout<<i<<endl;//            for(int j=head[i];j!=-1;j=edge[j].next)//                printf("%d ",edge[j].to);//            cout<<endl;//        }        solve();    }    return 0;}
0 0
原创粉丝点击