POJ 3678 2-SAT
题意:有n个顶点里面可以放数字1或0,给m个限制,每个限制给出两个顶点编号和两编号内数字运算后的结果
思路:很直接的2-SAT,每个点分为1和0两种情况,按限制要求建边,跑tarjan然后判断点是否在同一个强连通分量里就OK了
(一下代码是WA的。。找了一晚找不到BUG)
1 #include<cstdio> 2 const int maxn = 1e3+5; 3 int stack[maxn],dfn[maxn<<1],low[maxn<<1],head[maxn*maxn],dfs_num,top; 4 int color[maxn<<1],col_num; 5 bool vis[maxn*maxn]; 6 class edge 7 { 8 public: 9 int to,next; 10 }e[1000005]; 11 inline int gmin(int a,int b) 12 { 13 return a<b?a:b; 14 } 15 int ans; 16 void addedge(int u,int v) 17 { 18 e[++ans].next=head[u]; 19 e[ans].to=v; 20 head[u]=ans; 21 } 22 void Tarjan ( int x ) { 23 dfn[ x ] = ++dfs_num ; 24 low[ x ] = dfs_num ; 25 vis [ x ] = true ;//是否在栈中 26 stack [ ++top ] = x ; 27 for ( int i=head[ x ] ; i!=0 ; i=e[i].next ){ 28 int temp = e[ i ].to ; 29 if ( !dfn[ temp ] ){ 30 Tarjan ( temp ) ; 31 low[ x ] = gmin ( low[ x ] , low[ temp ] ) ; 32 } 33 else if ( vis[ temp ])low[ x ] = gmin ( low[ x ] , dfn[ temp ] ) ; 34 } 35 if ( dfn[ x ]==low[ x ] ) {//构成强连通分量 36 vis[ x ] = false ; 37 color[ x ] = ++col_num ;//染色 38 while ( stack[ top ] != x ) {//清空 39 color [stack[ top ]] = col_num ; 40 vis [ stack[ top-- ] ] = false ; 41 } 42 top -- ; 43 } 44 } 45 int main() 46 { 47 int n,m; 48 scanf("%d%d",&n,&m); 49 for(int i=0;i<m;i++) 50 { 51 int x,y,z; 52 char s[5]; 53 scanf("%d%d%d%s",&x,&y,&z,s); 54 if(s=="AND") 55 {if(z==1)addedge(2*x+1,2*x),addedge(2*y+1,2*y); 56 else addedge(2*x,2*y+1),addedge(2*y,2*x+1); 57 }else if(s=="OR") 58 {if(z==1)addedge(2*x+1,2*y),addedge(2*y+1,2*x); 59 else addedge(2*x,2*x+1),addedge(2*y,2*y+1); 60 }else{ 61 if(z==1)addedge(2*x,2*y+1),addedge(2*y+1,2*x),addedge(2*y,2*x+1),addedge(2*x+1,2*y); 62 else addedge(2*x,2*y),addedge(2*y,2*x),addedge(2*x+1,2*y+1),addedge(2*y+1,2*x+1); 63 } 64 } 65 66 for(int i=0;i<2*n;i++) 67 if(!dfn[i])Tarjan(i); 68 for(int i=0;i<n;i++) 69 if(color[2*i]==color[2*i+1]){printf("NO\n");return 0;} 70 printf("YES\n"); 71 return 0; 72 }
适当比较,砥砺前行