問題の意味:ある\(N \)変数\(X_1、x_nに関するの\) 、変数が与えられる可能な値0または1の各\(M \)番目の式、フォームの各式\(X_A \ ) \(OP \) \(X_b = C \)、ここでは\(B \) 2つの変数の数である\(C \)番号0または1、\(OPの\)がされている\(および\ )、\(あるいは\) 、\(XOR \) 。。3 ビットの動作の一すべての式が真であるように各変数の有効な割り当てがあるか否かを尋ねる\(N - <= 1000、M <= 10 6 ^ 。\)
分析:\(SAT-2 \)問題、最初に変換\(SAT-2 \)ノードの形で提供。(\)\表す\(X_A \)は、ノード、0値\(A + N \)表現\(X_A \) 1の値:
\(A \) \(および\) \(B = 0 \) 、次いで\(X_A = 1 \)場合、\(X_b \)がなければならない\(= 0 \)も有向エッジ\((A + N-、B)\) ..この思考ノートのような他の例は:でも、縁の条件を満足することができます:「Pであれば、必要Q」。
図は、RANの有向グラフの後に構築された\(Tarjan \)ノードが存在する場合、\(私は\) 、\(私は\)と\(I + N \)は同じ強連結成分に属し、その後、有効な割り当てがありませんA。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=1005;
const int M=4e6+5;
int tot,head[N],nxt[M],to[M];
int tim,top,num,dfn[N],low[N],st[M],color[N];
inline void add(int a,int b){nxt[++tot]=head[a];head[a]=tot;to[tot]=b;}
inline void tarjan(int u){
dfn[u]=low[u]=++tim;st[++top]=u;
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!color[v])low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
color[u]=++num;
while(st[top]!=u){
color[st[top]]=num;
--top;
}
--top;
}
}
int main(){
int n=read(),m=read();
for(int i=1;i<=m;++i){
int a=read(),b=read(),c=read();
++a;++b;string s;cin>>s;
if(s[0]=='A'){
if(c==0)add(a+n,b),add(b+n,a);
else add(a,a+n),add(b,b+n);
}
else if(s[0]=='O'){
if(c==0)add(a+n,a),add(b+n,b);
else add(a,b+n),add(b,a+n);
}
else if(s[0]=='X'){
if(c==0){
add(a,b);add(b,a);
add(a+n,b+n);add(b+n,a+n);
}
else{
add(a,b+n);add(b,a+n);
add(a+n,b);add(b+n,a);
}
}
}
for(int i=1;i<=n*2;++i)if(!dfn[i])tarjan(i);
for(int i=1;i<=n;++i)
if(color[i]==color[i+n]){
puts("NO");return 0;
}
puts("YES");
return 0;
}