Description:
有N个变量,每个变量取值可能是0或1,给定M个算式,表示a与b进行op运算结果为c,op为与、或、亦或的一种,求是否存在对每个变量的合法赋值
思路:
分三种情况讨论,建立2-sat模型,1 ~n表示该值取值为0,n+1 ~ 2n表示该值取值为1
1. a and b = 0。这表示如果a为1,b就必须为0,所以把(a+n,b)连有向边。同理,并将(b+n, a)连有向边
a and b = 1。这表示a和b必须为1,所以a为0,a就必须为1,然后将(a,a+n)连有向边,同理,将(b,b+n)连有向边
2. a or b = 1或者0。方法和上面差不多
3. a xor b = 1,这表示a如果为1,b必须为0,a如果为0,b必须为1。所以将(a+n,b)和(a,b+n)连有向边,同样的,连边(b,a+n),(b+n,a);
a xor b = 0,同上分析即可
#include<iostream> #include<cstring> #include<cstdio> #include<stack> using namespace std; const int N = 2010, M = 1e6 + 100; int head[N], now; struct edges{ int to, next, w; }edge[M<<1]; void add(int u, int v){ edge[++now] = {v, head[u]}; head[u] = now;} int n, m, dfn[N], cnt, low[N], dict[N], tot; bool ins[N]; stack<int> sta; void tarjan(int x){ dfn[x] = low[x] = ++cnt; sta.push(x); ins[x] = 1; for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(!dfn[v]){ tarjan(v); low[x] = min(low[x], low[v]); } else if(ins[v]) low[x] = min(low[x], dfn[v]); } if(dfn[x] == low[x]){ tot++; int tmp = -1; do{ tmp = sta.top(); sta.pop(); ins[tmp] = 0; dict[tmp] = tot; }while(tmp != x); } return ; } int main(){ scanf("%d%d", &n, &m); int x, y, c; char str[20]; bool flag = 0; for(int i = 1; i <= m; i++){ scanf("%d%d%d%s", &x, &y, &c, str); x++, y++; if(str[0] == ‘A‘){ if(!c) add(y + n, x), add(x + n, y); if(c) add(x, x + n), add(y, y + n); } if(str[0] == ‘O‘){ if(!c) add(x + n, x), add(y + n, y); if(c) add(y, x + n), add(x, y + n); } if(str[0] == ‘X‘){ if(!c) add(x, y), add(y, x), add(x + n, y + n), add(y + n, x + n); if(c) add(x, y + n), add(y, x + n), add(x + n, y), add(y + n, x); } } for(int i = 1; i <= 2 * n; i++) if(!dfn[i]) tarjan(i); for(int i = 1; i <= n; i++) if(dict[i] == dict[i + n]){ puts("NO"); return 0; } puts("YES"); return 0; }