hdu3062&&poj3678&&zoj3656 继续2-SAT

hdu3062链接:http://acm.hdu.edu.cn/showproblem.php?pid=3602
poj3678链接: http://poj.org/problem?id=3678
zoj3656链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3656

poj3678应该是最简单的吧~~
题意:有n个变量,每个可以取0或者1,再给出m组关系,每组关系都是两个变量进行运算可以得到的结果,运算有AND OR
XOR三种,问能否根据这些关系,判断每个变量的取值。
思路: 2-Sat问题,关键是要把所有情况考虑完全。用x表示该变量取0,x’表示取1,下面说下如何构图:
              a and b == 1,  a和b必须取1,所以连边a->a', b->b'.
              a and b == 0,  a和b不能同时为1,所以连边a'->b, b'->a.
              a  or  b == 1,  a和b不能同时为0,所以连边a->b', b->a'.
              a  or  b == 0,  a和b必须同时为0,所以连边a'->a, b'->b.
              a xor b == 1,  a和b取值要相反,所以连边a->b', a'->b, b->a', b'->a.
              a xor b == 0,  a和b取值要相同,所以连边a->b, b->a, a'->b', b'->a'.
              构图后强连通缩点判断有无解即可。

View Code
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 #define N 2005
 6 #define M 2000005
 7 int n,m,cnt,scnt,top,edgeNum;
 8 int low[N],dfn[N],stack[N],id[N],head[N];
 9 bool instack[N];
10 struct edge{int v,next;}edge[M];
11 void add(int a,int b){
12     edge[edgeNum].v=b;
13     edge[edgeNum].next=head[a];
14     head[a]=edgeNum++;
15 }
16 void dfs(int x){
17     low[x]=dfn[x]=++cnt;
18     stack[++top]=x;
19     instack[x]=1;
20     int v;
21     for(int i=head[x];i!=-1;i=edge[i].next){
22         v=edge[i].v;
23         if(!dfn[v]){
24             dfs(v);
25             low[x]=low[v]<low[x]?low[v]:low[x];
26         }else if(instack[v]&&dfn[v]<low[x]){
27             low[x]=dfn[v];
28         }
29     }
30     if(low[x]==dfn[x]){
31         scnt++;
32         do{
33             v=stack[top--];
34             instack[v]=0;
35             id[v]=scnt;
36         }while(v!=x);
37     }
38     return ;
39 }
40 bool solve(){
41     cnt=scnt=top=0;
42     memset(dfn,0,sizeof(dfn));
43     memset(instack,0,sizeof(instack));
44     for(int i=0;i<2*n;i++){
45         if(!dfn[i]) dfs(i);
46     }
47     for(int i=0;i<2*n;i+=2){
48         if(id[i]==id[i^1]) return 0;
49     }
50     return 1;
51 }
52 int main()
53 {
54     char ch[5];
55     int a,b,c;
56     while(~scanf("%d%d",&n,&m)){
57         edgeNum=0;
58         memset(id,0,sizeof(id));
59         memset(head,-1,sizeof(head));
60         for(int i=0;i<m;i++){
61             scanf("%d%d%d%s",&a,&b,&c,&ch);
62             a=a<<1;b=b<<1;
63             if(strcmp(ch,"AND")==0){
64                 if(c) add(a,a^1),add(b,b^1);
65                 else add(a^1,b),add(b^1,a);
66             } else if(strcmp(ch,"OR")==0){
67                 if(c) add(a,b^1),add(b,a^1);
68                 else add(a^1,a),add(b^1,b);
69             }else{
70                 if(c) add(a,b^1),add(b,a^1),add(a^1,b),add(b^1,a);
71                 else add(a,b),add(a^1,b^1),add(b,a),add(b^1,a^1);
72             }
73         }
74         if(solve()) puts("YES");
75         else puts("NO");
76     }
77     return 0;
78 }

zoj3656(长春赛现场赛B题)~和poj3678差不多,只是n个变量不是0或者1,而是0~2 ^ 31 - 1,这时只需要枚举这31位即可,把poj3678循环31次就好了。

View Code
  1 //zoj 3656 1300+ms
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 using namespace std;
  6 #define N 1005
  7 #define M 500005
  8 int n,cnt,scnt,top,edgeNum;
  9 int B[N][N];
 10 int low[N],dfn[N],stack[N],id[N],head[N];
 11 bool instack[N];
 12 struct edge{int v,next;}edge[M];
 13 void add(int a,int b){
 14     edge[edgeNum].v=b;
 15     edge[edgeNum].next=head[a];
 16     head[a]=edgeNum++;
 17 }
 18 void dfs(int x){
 19     low[x]=dfn[x]=++cnt;
 20     stack[++top]=x;
 21     instack[x]=1;
 22     int v;
 23     for(int i=head[x];i!=-1;i=edge[i].next){
 24         v=edge[i].v;
 25         if(!dfn[v]){
 26             dfs(v);
 27             low[x]=low[v]<low[x]?low[v]:low[x];
 28         }else if(instack[v]&&dfn[v]<low[x]){
 29             low[x]=dfn[v];
 30         }
 31     }
 32     if(low[x]==dfn[x]){
 33         scnt++;
 34         do{
 35             v=stack[top--];
 36             instack[v]=0;
 37             id[v]=scnt;
 38         }while(v!=x);
 39     }
 40     return ;
 41 }
 42 bool solve(){
 43     cnt=scnt=top=0;
 44     memset(dfn,0,sizeof(dfn));
 45     memset(instack,0,sizeof(instack));
 46     for(int i=0;i<2*n;i++){
 47         if(!dfn[i]) dfs(i);
 48     }
 49     for(int i=0;i<2*n;i+=2){
 50         if(id[i]==id[i^1]) return 0;
 51     }
 52     return 1;
 53 }
 54 void build(int i,int j,int a,int b,int c){
 55     if(i%2==1&&j%2==1){
 56         if(c) add(a,b^1),add(b,a^1);
 57         else add(a^1,a),add(b^1,b);
 58     }else if(i%2==0&&j%2==0){
 59         if(c) add(a,a^1),add(b,b^1);
 60         else add(a^1,b),add(b^1,a);
 61     }else{
 62         if(c) add(a,b^1),add(b,a^1),add(a^1,b),add(b^1,a);
 63         else add(a,b),add(a^1,b^1),add(b,a),add(b^1,a^1);
 64     }
 65 }
 66 int main()
 67 {
 68     char ch[5];
 69     int a,b,c;
 70     while(scanf("%d",&n)!=EOF){
 71         int flag=1;
 72 
 73         for(int i=0;i<n;i++)
 74             for(int j=0;j<n;j++){
 75             scanf("%d",&B[i][j]);
 76             if(i==j&&B[i][j]!=0) flag=0;
 77         }
 78 
 79         if(flag)
 80         for(int i=0;i<n;i++){
 81             for(int j=i+1;j<n;j++)
 82                 if(B[i][j]!=B[j][i]){
 83                     flag=0;
 84                     break;
 85                 }
 86             if(!flag)break;
 87         }
 88 
 89         if(flag)
 90         for(int k=0;k<31;k++){
 91             edgeNum=0;
 92             memset(id,0,sizeof(id));
 93             memset(head,-1,sizeof(head));
 94             for(int i=0;i<n;i++){
 95                 for(int j=i+1;j<n;j++){
 96                     if(i==j) continue;
 97                     a=i<<1;
 98                     b=j<<1;
 99                     c=B[i][j]&(1<<k);
100                     build(i,j,a,b,c);
101                 }
102             }
103             if(!solve()) {flag=0;break;}//一开始写到了循环最里层,TLE了好几次都没发现错误,图还没建好就solve了……@#¥*&……
104         }
105         if(flag) puts("YES");
106         else puts("NO");
107     }
108     return 0;
109 }

 hdu3062比较简单一些:

View Code
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 #define N 2005
 6 #define M 1000005
 7 int n,m,cnt,scnt,top,edgeNum;
 8 int low[N],dfn[N],stack[N],id[N],head[N];
 9 bool instack[N];
10 struct edge{int v,next;}edge[M];
11 void add(int a,int b){
12     edge[edgeNum].v=b;
13     edge[edgeNum].next=head[a];
14     head[a]=edgeNum++;
15 }
16 void dfs(int x){
17     low[x]=dfn[x]=++cnt;
18     stack[++top]=x;
19     instack[x]=1;
20     int v;
21     for(int i=head[x];i!=-1;i=edge[i].next){
22         v=edge[i].v;
23         if(!dfn[v]){
24             dfs(v);
25             low[x]=low[v]<low[x]?low[v]:low[x];
26         }else if(instack[v]&&dfn[v]<low[x]){
27             low[x]=dfn[v];
28         }
29     }
30     if(low[x]==dfn[x]){
31         scnt++;
32         do{
33             v=stack[top--];
34             instack[v]=0;
35             id[v]=scnt;
36         }while(v!=x);
37     }
38     return ;
39 }
40 bool solve(){
41     cnt=scnt=top=0;
42     memset(dfn,0,sizeof(dfn));
43     memset(instack,0,sizeof(instack));
44     for(int i=0;i<2*n;i++){
45         if(!dfn[i]) dfs(i);
46     }
47     for(int i=0;i<2*n;i+=2){
48         if(id[i]==id[i^1]) return 0;
49     }
50     return 1;
51 }
52 int main()
53 {
54     int a1,a2,c1,c2;
55     while(scanf("%d%d",&n,&m)!=EOF){
56         edgeNum=0;
57         memset(id,0,sizeof(id));
58         memset(head,-1,sizeof(head));
59         for(int i=0;i<m;i++){
60             scanf("%d%d%d%d",&a1,&a2,&c1,&c2);
61             a1<<=1;a2<<=1;
62             add(a1+c1,a2+(c2^1));
63             add(a2+c2,a1+(c1^1));
64         }
65         if(solve()) puts("YES");
66         else puts("NO");
67     }
68     return 0;
69 }


 

posted @ 2012-11-05 21:31  _sunshine  阅读(394)  评论(0编辑  收藏  举报