poj3678 Katu Puzzle
强联通没啥好写的,写写2-sat的题解算了。
拆点,一个表示这个数取0,另一个表示取1
2-sat边的意义是选了x,就必须选y。
那么分情况讨论建边即可。值得注意的是,假如是and运算,答案为0,那么1必然不能选,那么让当前位置的1节点连向自己的0节点,直接产生不合法情况。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,next; }a[8100000];int len,last[2100]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int z,dfn[2100],low[2100]; int top,sta[2100];bool v[2100]; int cnt,bel[2100]; void SCC(int x) { dfn[x]=low[x]=++z; sta[++top]=x;v[x]=true; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(dfn[y]==0) { SCC(y); low[x]=min(low[x],low[y]); } else if(v[y]==true) low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]) { int k;cnt++; do { k=sta[top];top--; v[k]=false; bel[k]=cnt; }while(k!=x); } } int n,m; void conposition() { int x,y,z;char ss[10]; len=0;memset(last,0,sizeof(last)); for(int i=1;i<=m;i++) { scanf("%d%d%d%s",&x,&y,&z,ss+1);x++,y++; if(ss[1]=='A') { if(z==0) ins(x+n,y), ins(y+n,x); else ins(x,x+n), ins(y,y+n); } else if(ss[1]=='O') { if(z==0) ins(x+n,x), ins(y+n,y); else ins(x,y+n), ins(y,x+n); } else { if(z==0) ins(x,y), ins(x+n,y+n), ins(y,x), ins(y+n,x+n); else ins(x,y+n), ins(x+n,y), ins(y,x+n), ins(y+n,x); } } } int main() { scanf("%d%d",&n,&m);conposition(); z=top=cnt=0; for(int i=1;i<=2*n;i++) if(dfn[i]==0)SCC(i); for(int i=1;i<=n;i++) if(bel[i]==bel[i+n]){printf("NO\n");return 0;} printf("YES\n"); return 0; }
pain and happy in the cruel world.