有N个变量X0~XN−1,每个变量的可能取值为0或1。
给定M个算式,每个算式形如 XaopXb=c,其中 a,b 是变量编号,c 是数字0或1,op 是 and,or,xor 三个位运算之一。
求是否存在对每个变量的合法赋值,使所有算式都成立。
输入格式
第一行包含两个整数N和M。
接下来M行,每行包含三个整数a b c,以及一个位运算(AND,OR,XOR中的一个)。
输出格式
输出结果,如果存在,输出“YES”,否则输出“NO”
数据范围
1≤N≤1000,
1≤M≤106
输入样例:
4 4
0 1 1 AND
1 2 1 OR
3 2 0 AND
3 0 0 XOR
输出样例:
YES
边很多,故不能拓展并查集,需要求SCC,然后相当于就是2-SAT问题。
找到每个之间的关系即可。
a为1,a+n为0
注意AND时,c为1,直接若有0,产生矛盾即可add(a+n,a),add(b+n,b)。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=2e3+10,M=1e7+10;
int n,m,vis[N];
int dfn[N],low[N],col[N],co,cnt;
int head[N],nex[M],to[M],tot;
stack<int> st;
inline void add(int a,int b){to[++tot]=b; nex[tot]=head[a]; head[a]=tot;}
void tarjan(int x){
dfn[x]=low[x]=++cnt; vis[x]=1; st.push(x);
for(int i=head[x];i;i=nex[i]){
if(!dfn[to[i]]){
tarjan(to[i]); low[x]=min(low[x],low[to[i]]);
}else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);
}
if(dfn[x]==low[x]){
int u; co++;
do{
u=st.top(); st.pop(); vis[u]=0; col[u]=co;
}while(u!=x);
}
}
signed main(){
cin>>n>>m;
for(int i=1,a,b,c;i<=m;i++){
char op[5]; scanf("%d %d %d %s",&a,&b,&c,op); ++a,++b;
if(op[0]=='A'){
if(c) add(a+n,a),add(b+n,b);
else add(a,b+n),add(b,a+n);
}else if(op[0]=='O'){
if(c) add(a+n,b),add(b+n,a);
else add(a,a+n),add(b,b+n);
}else{
if(c) add(a,b+n),add(b,a+n),add(a+n,b),add(b+n,a);
else add(a+n,b+n),add(a,b),add(b,a),add(b+n,a+n);
}
}
for(int i=1;i<=(n<<1);i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++) if(col[i]==col[i+n]) return puts("NO"),0;
puts("YES");
return 0;
}