很神奇的2-SAT问题。找了一篇赵爽的《2-SAT解法浅析》。作者是高中生啊,查了下却发现是05年交大ACM总冠军队的成员……Orz
题目抽象出来后就不难做了,建一个含2*N个点的有向图,边由逻辑运算给出,边(u,v)表示选了u点则必须选v。编号为i的点对应图中i*2和i*2+1的两个点,分别表示i点取值为1、0。点A、B间由逻辑运算生成的边如下:
A & B == 1: 增加边(A*2+1,A*2)和(B*2+1,B*2);
A & B == 0: 增加边(A*2,B*2+1)和(B*2,A*2+1);
A | B == 1: 增加边(B*2+1,A*2)和(A*2+1,B*2);
A | B == 0: 增加边(A*2,A*2+1)和(B*2,B*2+1);
A ^ B == 1: 增加边(A*2,B*2+1)、(B*2+1,A*2)、(A*2+1,B*2)和(B*2,A*2+1);
A ^ B == 0: 增加边(A*2,B*2)、(B*2,A*2)、(A*2+1,B*2+1)和(B*2+1,A*2+1);
建好图后求强连通分量。最后判断是否对所有的i=0:N-1,是否有i*2和i*2+1不在同一强连通分量中,若成立则原问题有解,否则无解。
这里被 A & B == 1 和 A | B == 0 卡了一下……不可取的点直接引入必败边的做法非常巧妙……
同样分别使用了两次DFS和tarjan来求强连通分量,代码分别如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
#include<cstdio> #include<cstring> int n,m,hd[2000],hdr[2000],el,erl,b[2000],f[2000],v[2000],vl; char s[4]; int xa,xb,c; struct edge { int j,p; }e[4000000],er[4000000]; int fi(int i) { if(f[i]<0) return i; else return f[i]=fi(f[i]); } inline void un(int a,int b) { int fa=fi(a),fb=fi(b); if(fa==fb) return; int na=f[fa],nb=f[fb]; if(na<nb) { f[fa]+=nb; f[fb]=fa; } else { f[fb]+=na; f[fa]=fb; } } inline void adde() { int a0=xa*2,a1=xa*2+1,b0=xb*2,b1=xb*2+1; if(s[0]=='A') { if(c==1) { e[el].j=a0; e[el].p=hd[a1]; hd[a1]=el++; e[el].j=b0; e[el].p=hd[b1]; hd[b1];el++; er[erl].j=a1; er[erl].p=hdr[a0]; hdr[a0]=erl++; er[erl].j=b1; er[erl].p=hdr[b0]; hdr[b0]=erl++; } else { e[el].j=b1; e[el].p=hd[a0]; hd[a0]=el++; e[el].j=a1; e[el].p=hd[b0]; hd[b0]=el++; er[erl].j=a0; er[erl].p=hdr[b1]; hdr[b1]=erl++; er[erl].j=b0; er[erl].p=hdr[a1]; hdr[a1]=erl++; } } else if(s[0]=='O') { if(c==1) { e[el].j=b0; e[el].p=hd[a1]; hd[a1]=el++; e[el].j=a0; e[el].p=hd[b1]; hd[b1]=el++; er[erl].j=a1; er[erl].p=hdr[b0]; hdr[b0]=erl++; er[erl].j=b1; er[erl].p=hdr[a0]; hdr[a0]=erl++; } else { e[el].j=a1; e[el].p=hd[a0]; hd[a0]=el++; e[el].j=b1; e[el].p=hd[b0]; hd[b0]=el++; er[erl].j=a0; er[erl].p=hdr[a1]; hdr[a1]=erl++; er[erl].j=b0; er[erl].p=hdr[b1]; hdr[b1]=erl++; } } else { if(c==1) { e[el].j=b1; e[el].p=hd[a0]; hd[a0]=el++; e[el].j=a0; e[el].p=hd[b1]; hd[b1]=el++; er[erl].j=a0; er[erl].p=hdr[b1]; hdr[b1]=erl++; er[erl].j=b1; er[erl].p=hdr[a0]; hdr[a0]=erl++; e[el].j=b0; e[el].p=hd[a1]; hd[a1]=el++; e[el].j=a1; e[el].p=hd[b0]; hd[b0]=el++; er[erl].j=a1; er[erl].p=hdr[b0]; hdr[b0]=erl++; er[erl].j=b0; er[erl].p=hdr[a1]; hdr[a1]=erl++; } else { e[el].j=b0; e[el].p=hd[a0]; hd[a0]=el++; e[el].j=a0; e[el].p=hd[b0]; hd[b0]=el++; er[erl].j=a0; er[erl].p=hdr[b0]; hdr[b0]=erl++; er[erl].j=b0; er[erl].p=hdr[a0]; hdr[a0]=erl++; e[el].j=b1; e[el].p=hd[a1]; hd[a1]=el++; e[el].j=a1; e[el].p=hd[b1]; hd[b1]=el++; er[erl].j=a1; er[erl].p=hdr[b1]; hdr[b1]=erl++; er[erl].j=b1; er[erl].p=hdr[a1]; hdr[a1]=erl++; } } } void DFS(int i) { int j,k,l; b[i]=1; for(l=hd[i];l!=-1;l=e[l].p) { j=e[l].j; if(b[j]) continue; DFS(j); } v[vl++]=i; } void DFSr(int i) { int j,k,l; b[i]=1; for(l=hdr[i];l!=-1;l=er[l].p) { j=er[l].j; if(b[j]) continue; un(i,j); DFSr(j); } } int chk() { int i; for(i=0;i<n;i++) if(fi(i*2)==fi(i*2+1)) return 0; return 1; } int main() { int i,j,k,l; while(~scanf("%d%d",&n,&m)) { el=erl=vl=0; memset(hd,-1,sizeof hd); memset(hdr,-1,sizeof hdr); memset(f,-1,sizeof f); while(m--) { scanf("%d%d%d%s",&xa,&xb,&c,s); adde(); } memset(b,0,sizeof b); for(i=0;i<2*n;i++) if(!b[i]) DFS(i); memset(b,0,sizeof b); for(i=vl-1;i>-1;i--) if(!b[v[i]]) DFSr(v[i]); puts(chk()?"YES":"NO"); } return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
#include<cstdio> #include<cstring> int n,m,hd[2000],hdr[2000],el,erl,b[2000],f[2000]; int st[2000],sl,stb[2000],low[2000]; char s[4]; int xa,xb,c; struct edge { int j,p; }e[4000000],er[4000000]; int fi(int i) { if(f[i]<0) return i; else return f[i]=fi(f[i]); } inline void un(int a,int b) { int fa=fi(a),fb=fi(b); if(fa==fb) return; int na=f[fa],nb=f[fb]; if(na<nb) { f[fa]+=nb; f[fb]=fa; } else { f[fb]+=na; f[fa]=fb; } } inline void adde() { int a0=xa*2,a1=xa*2+1,b0=xb*2,b1=xb*2+1; if(s[0]=='A') { if(c==1) { e[el].j=a0; e[el].p=hd[a1]; hd[a1]=el++; e[el].j=b0; e[el].p=hd[b1]; hd[b1];el++; er[erl].j=a1; er[erl].p=hdr[a0]; hdr[a0]=erl++; er[erl].j=b1; er[erl].p=hdr[b0]; hdr[b0]=erl++; } else { e[el].j=b1; e[el].p=hd[a0]; hd[a0]=el++; e[el].j=a1; e[el].p=hd[b0]; hd[b0]=el++; er[erl].j=a0; er[erl].p=hdr[b1]; hdr[b1]=erl++; er[erl].j=b0; er[erl].p=hdr[a1]; hdr[a1]=erl++; } } else if(s[0]=='O') { if(c==1) { e[el].j=b0; e[el].p=hd[a1]; hd[a1]=el++; e[el].j=a0; e[el].p=hd[b1]; hd[b1]=el++; er[erl].j=a1; er[erl].p=hdr[b0]; hdr[b0]=erl++; er[erl].j=b1; er[erl].p=hdr[a0]; hdr[a0]=erl++; } else { e[el].j=a1; e[el].p=hd[a0]; hd[a0]=el++; e[el].j=b1; e[el].p=hd[b0]; hd[b0]=el++; er[erl].j=a0; er[erl].p=hdr[a1]; hdr[a1]=erl++; er[erl].j=b0; er[erl].p=hdr[b1]; hdr[b1]=erl++; } } else { if(c==1) { e[el].j=b1; e[el].p=hd[a0]; hd[a0]=el++; e[el].j=a0; e[el].p=hd[b1]; hd[b1]=el++; er[erl].j=a0; er[erl].p=hdr[b1]; hdr[b1]=erl++; er[erl].j=b1; er[erl].p=hdr[a0]; hdr[a0]=erl++; e[el].j=b0; e[el].p=hd[a1]; hd[a1]=el++; e[el].j=a1; e[el].p=hd[b0]; hd[b0]=el++; er[erl].j=a1; er[erl].p=hdr[b0]; hdr[b0]=erl++; er[erl].j=b0; er[erl].p=hdr[a1]; hdr[a1]=erl++; } else { e[el].j=b0; e[el].p=hd[a0]; hd[a0]=el++; e[el].j=a0; e[el].p=hd[b0]; hd[b0]=el++; er[erl].j=a0; er[erl].p=hdr[b0]; hdr[b0]=erl++; er[erl].j=b0; er[erl].p=hdr[a0]; hdr[a0]=erl++; e[el].j=b1; e[el].p=hd[a1]; hd[a1]=el++; e[el].j=a1; e[el].p=hd[b1]; hd[b1]=el++; er[erl].j=a1; er[erl].p=hdr[b1]; hdr[b1]=erl++; er[erl].j=b1; er[erl].p=hdr[a1]; hdr[a1]=erl++; } } } void tarjan(int i,int d) { int j,k,l; b[i]=1; stb[i]=1; st[sl++]=i; low[i]=d; for(l=hd[i];l!=-1;l=e[l].p) { j=e[l].j; if(!b[j]) { tarjan(j,d+1); low[i]=low[j]<low[i]?low[j]:low[i]; } else if(stb[j]) low[i]=low[j]<low[i]?low[j]:low[i]; } if(low[i]==d) { while(1) { sl--; un(i,st[sl]); if(st[sl]==i) break; } } } int chk() { int i; for(i=0;i<n;i++) if(fi(i*2)==fi(i*2+1)) return 0; return 1; } int main() { int i,j,k,l; while(~scanf("%d%d",&n,&m)) { el=erl=0; memset(hd,-1,sizeof hd); memset(hdr,-1,sizeof hdr); memset(f,-1,sizeof f); while(m--) { scanf("%d%d%d%s",&xa,&xb,&c,s); adde(); } sl=0; memset(b,0,sizeof b); for(i=0;i<2*n;i++) { memset(stb,0,sizeof stb); if(!b[i]) tarjan(i,1); } puts(chk()?"YES":"NO"); } return 0; } |