有N个变量X1X1~XNXN,每个变量的可能取值为0或1。
给定M个算式,每个算式形如 XaopXb=cXaopXb=c,其中 a,b 是变量编号,c 是数字0或1,op 是 and,or,xor 三个位运算之一。
求是否存在对每个变量的合法赋值,使所有算式都成立。
输入格式
第一行包含两个整数N和M。
接下来M行,每行包含三个整数a b c,以及一个位运算(AND,OR,XOR中的一个)。
输出格式
输出结果,如果存在,输出“YES”,否则输出“NO”
数据范围
1≤N≤10001≤N≤1000,
1≤M≤1061≤M≤106
输入样例:
4 4
0 1 1 AND
1 2 1 OR
3 2 0 AND
3 0 0 XOR
输出样例:
YES
思路:根据题意,该题是一个 2-SAT 问题,将操作符进行转换,进行判定即可
对于 A[x],可以通过连边 <x',x> 实现,NOT A[x],可以通过连边 <x,x'> 来实现,对于 NOT(A[x] AND A[y]) 需要连两条边 <x, y'> 和 <y, x'> 来实现,对于 A[x] OR A[y] 需要连两条边 <x', y> 和 <y', x> 来实现
故对于 and、or、xor 三种运算有:
and 运算:
a and b = 0 时:若 a=1,则必定满足 b=0;若 b=1,则必定满足 a=0,即:<a,1,b,0>、<b,1,a,0>
a and b = 1 时:a=1 且 b=1,即:<a,0,a,1>、<b,0,b,1>
or 运算:
a or b = 0 时:a = 0 且 b = 0,即:<a,1,a,0>、<b,1,b,0>
a or b = 1 时:若 a=0,则必定满足 b=1;若 b=0,则必定满足 a=0,即:<a,0,b,1>、<b,0,a,1>
xor 运算:
a xor b = 0 时,有以下四种情况:
若 a = 0,则必定满足 b = 0,即:<a,0,b,0>
若 b = 0,则必定满足 a = 0,即:<b,0,a,0>
若 a = 1,则必定满足 b = 1,即:<a,1,b,1>
若 b = 1,则必定满足 a = 1,即:<b,1,a,1>
a xor b = 1 时,有以下四种情况:
若 a = 0,则必定满足 b = 1,即:<a,0,b,1>
若 b = 0,则必定满足 a = 1,即:<b,0,a,1>
若 a = 1,则必定满足 b = 0,即:<a,1,b,0>
若 b = 1,则必定满足 a = 0,即:<b,1,a,0>
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; #define debug(x) cout << "fuck bug " << x << " "; #define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) const int maxn = 4e5 + 7; typedef long long ll; int n,m; struct edge { int to,nxt; }e[maxn]; int head[maxn],tot; void add(int u ,int v){ e[++tot].to = v; e[tot].nxt = head[u]; head[u] = tot; } int dfn[maxn],low[maxn],num,inStack[maxn]; int stack[maxn],top,cnt,C[maxn]; void tarjan(int x) { dfn[x] = low[x] = ++num; stack[++top] = x; inStack[x] = true; for (int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if (dfn[y] == 0) { tarjan(y); low[x] = min(low[x], low[y]); } else if (inStack[y]) { low[x] = min(low[x], low[y]); } } if (low[x] == dfn[x]) { cnt++; int z; do { z = stack[top--]; inStack[z] = false; C[z] = cnt; } while (z != x); } } int main(int argc, char const *argv[]) { //cin >> n >> m; scanf("%d %d",&n,&m); for(int i = 1;i <= m ; i ++){ int a , b , c ; char str[10]; //cin >> a >> b >> c >> str; scanf("%d %d %d %s",&a,&b,&c,str); if(str[0] == 'A'){ if(c == 1){ add(a,a+n); add(b,b+n); }else{ add(a+n,b); add(b+n,a); } }else if(str[0] == 'O'){ if(c == 1){ add(a,b+n); add(b,a+n); }else{ add(a+n,a); add(b+n,b); } }else if(str[0] == 'X'){ if(c == 1){ add(a,b+n); add(b,a+n); add(a+n,b); add(b+n,a); }else{ add(a,b); add(b,a); add(a+n,b+n); add(b+n,a+n); } } } for(int i = 0;i < n + n; i++){ if(!dfn[i]) tarjan(i); } bool flag=1; for(int i = 0;i < n ;i ++){ if(C[i] == C[i + n]) { flag = 0; break; } } if(flag) puts("YES"); else puts("NO"); return 0; }