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'.
构图后强连通缩点判断有无解即可。
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次就好了。
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比较简单一些:
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 }