题意:欲构建n个点m条边的图,限制为:定点只能取01二值之一。对每条边给出如下信息:连接的两个顶点、一种预算('&'、'|'、'^'三种之一)和一个值(0或1),要求两个顶点的取值进行对应运算得到给定值。问满足输入限制的图能否构建成功:
思路:2-SAT。对每个定点i,i表示取0,i+n表示取1;枚举三种运算和给定结果建图。
#include <stdio.h> #include <string.h> #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define N 10010 struct edge{ int y,next; }e[8*1000010]; int n,m,component,top,tops,id; int first[N],dfn[N],low[N],stack[N],strong[N]; void init(){ tops = -1; top = component = id = 0; memset(first,-1,sizeof(first)); memset(dfn,-1,sizeof(dfn)); memset(strong,0,sizeof(strong)); } void add(int x,int y){ e[top].y = y; e[top].next = first[x]; first[x] = top++; } void tarjan(int x){ int i,y; dfn[x] = low[x] = ++id; stack[++tops] = x; for(i = first[x];i!=-1;i=e[i].next){ y = e[i].y; if(dfn[y] == -1){ tarjan(y); low[x] = min(low[x],low[y]); } else if(!strong[y]) low[x] = min(low[x],dfn[y]); } if(dfn[x] == low[x]){ component++; do{ strong[stack[tops]] = component; }while(stack[tops--] != x); } } int main(){ int i,j; freopen("a.txt","r",stdin); while(scanf("%d %d",&n,&m)!=EOF){ int i,j,a,b,c; char s[5]; init(); for(i = 1;i<=m;i++){ scanf("%d %d %d %s",&a,&b,&c,s); if(!strcmp(s,"AND")){ if(c){ add(a,b);add(a,b+n); add(b,a);add(b,a+n); add(a+n,b+n);add(b+n,a+n); }else{ add(a+n,b);add(b+n,a); } }else if(!strcmp(s,"OR")){ if(c){ add(a,b+n);add(b,a+n); }else{ add(a+n,b);add(a+n,b+n); add(b+n,a);add(b+n,a+n); add(a,b);add(b,a); } }else{ if(c){ add(a,b+n);add(a+n,b); add(b,a+n);add(b+n,a); }else{ add(a,b);add(a+n,b+n); add(b,a);add(b+n,a+n); } } } for(i = 0;i<2*n;i++) if(dfn[i] == -1) tarjan(i); for(i = 0;i<n;i++) if(strong[i] && (strong[i] == strong[i+n])) break; if(i>=n) printf("YES\n"); else printf("NO\n"); } return 0; }