poj3648 2-SAT

题目链接:http://poj.org/problem?id=3648

题意有点纠结:

一堆夫妇去参加一对新人的婚礼。人们坐在一个很长很长的桌子的两侧(面对面)。新郎新娘在桌子头面对面座。

新娘不希望看见她对面的一排有一对夫妇坐着(夫妇需要分开两排座)。

同时,一些人之间有通奸关系,新娘也不希望有通奸关系的人同时坐在她对面的一排。

问你可否满足新娘的要求,可以的话,输出一种方案

思路:

把丈夫和新娘同一边看做点i,在新娘对面看做i+n。然后根据通奸关系进行构图。因为新郎也有可能有通奸关系,

所以构图时加入新郎点0,增加一条边,0-->0+n。然后就是求解2-SAT问题了。

第一道2-SAT问题,好几天没刷题了,惭愧ing,好好加油!!前端时间写了一道强连通分量+拓扑排序,这道题目就简单多了:其实

也是强连通分量+拓扑排序,但是建图是还是关键的。

强烈推荐去看看《由对称性解2-SAT问题》,讲的很清晰。

View Code
  1 #include <stdio.h>
  2 #include <queue>
  3 #include <string.h>
  4 #include <iostream>
  5 using namespace std;
  6 #define M 2005
  7 #define N 3000010
  8 int head[M],head1[M];//head[],edgeNum,edge[]是建的图
  9 int edgeNum,edgeNum1;//head1[],edgeNum1,edge1[]是缩点后的图
 10 int cnt,scnt,begin,n,m;//begin是栈顶
 11 int low[M],dfn[M],stack[M],id[M];
 12 int oppo[M],in[M],col[M];//in[]是拓扑排序的入度,oppo[]记录互相矛盾的点
 13 bool instack[M],ans[M];//instack[]标志是否在栈中,ans[]标记是否在新娘这边
 14 struct edge{int v,next;}edge[N],edge1[N];
 15 void add(int a,int b){
 16     edge[edgeNum].v=b;
 17     edge[edgeNum].next=head[a];
 18     head[a]=edgeNum++;
 19 }
 20 void add1(int a,int b){
 21     edge1[edgeNum1].v=b;
 22     edge1[edgeNum1].next=head1[a];
 23     head1[a]=edgeNum1++;
 24 }
 25 void dfs(int x){
 26     low[x]=dfn[x]=++cnt;
 27     stack[++begin]=x;
 28     instack[x]=1;
 29     int v;
 30     for(int i=head[x];i!=-1;i=edge[i].next){
 31         v=edge[i].v;
 32         if(!dfn[v]){
 33             dfs(v);
 34             low[x]=low[v]<low[x]?low[v]:low[x];
 35         }else if(instack[v]&&dfn[v]<low[x]){
 36             low[x]=dfn[v];
 37         }
 38     }
 39     if(low[x]==dfn[x]){
 40         scnt++;
 41         do{
 42             v=stack[begin--];
 43             instack[v]=0;
 44             id[v]=scnt;
 45         }while(v!=x);
 46     }
 47     return ;
 48 }
 49 bool solve(int n){
 50     cnt=scnt=begin=0;
 51     memset(dfn,0,sizeof(dfn));
 52     memset(instack,0,sizeof(instack));
 53     for(int i=0;i<2*n;i++){
 54         if(!dfn[i]) dfs(i);
 55     }
 56     for(int i=0;i<n;i++){
 57 //若有同一组的分量在同一个强连通分量中,则直接返回0
 58         if(id[i]==id[i+n]) return 0;
 59 //存储同一组的分量所在哪个强连通分量,这样访问过其中一个后,另一个就不用再去访问了
 60         oppo[id[i]]=id[i+n];
 61 //在缩点的图中标记互斥的缩点。(原来互斥,现在也互斥)
 62         oppo[id[i+n]]=id[i];
 63     }
 64     memset(in,0,sizeof(in));
 65     memset(col,0,sizeof(col));
 66 //缩点后建立图,add1(a,b)增加边
 67     for(int i=0;i<2*n;i++)
 68         for(int j=head[i];j!=-1;j=edge[j].next){
 69             int v=edge[j].v;
 70             if(id[i]!=id[v]){
 71                 in[id[i]]++;
 72                 add1(id[v],id[i]);
 73             }
 74         }
 75 //拓扑排序
 76     queue<int> que;
 77     for(int i=0;i<=scnt;i++){
 78         if(!in[i]) que.push(i);
 79     }
 80     while(!que.empty()){
 81         int now=que.front();
 82         que.pop();
 83         if(col[now]==0){//对于未着色的点x,将x染成红色1,同时将与x矛盾的点oppo[x]染成蓝色-1。
 84             col[now]=1;
 85             col[oppo[now]]=-1;
 86         }
 87         for(int i=head1[now];i!=-1;i=edge1[i].next){
 88             int v=edge1[i].v;
 89             if(--in[v]==0) que.push(v);
 90         }
 91     }
 92     memset(ans,0,sizeof(ans));
 93     for(int i=0;i<n;i++){
 94         if(col[id[i]]==1) ans[i]=1;
 95     }
 96     return 1;
 97 }
 98 int main(){
 99     int a,b;
100     char c,d;
101     while(scanf("%d%d",&n,&m)!=EOF){
102         if(!n&&!m) break;
103         edgeNum=edgeNum1=0;
104         memset(in,0,sizeof(in));
105         memset(id,0,sizeof(id));
106         memset(head,-1,sizeof(head));
107         memset(head1,-1,sizeof(head1));
108         while(m--){
109             scanf("%d%c %d%c",&a,&c,&b,&d);
110             if(c=='h'&&d=='h') {add(b+n,a);add(a+n,b);}
111             if(c=='h'&&d=='w') {add(a+n,b+n);add(b,a);}
112             if(c=='w'&&d=='h') {add(a,b);add(b+n,a+n);}
113             if(c=='w'&&d=='w') {add(a,b+n);add(b,a+n);}
114         }
115         add(0,0+n);//增加新娘到新郎的边
116         if(solve(n)){
117             for(int i=1;i<n;i++){
118                 if(ans[i]) printf("%dh ",i);
119                 else printf("%dw ",i);
120             }
121             printf("\n");
122         }
123         else puts("bad luck");
124     }
125     return 0;
126 }

 

posted @ 2012-11-02 18:09  _sunshine  阅读(555)  评论(2编辑  收藏  举报