这题是2-SAT的经典题,鉴于n*m挺大的,所以就用强连通缩点的方式检验。
3种逻辑操作很简单,建边不难,注意对称性。
如果碰到 A && B==1 -> A=B=1
建立边是 从 ~A到A,从~B到B 连一条的。
其他的注意细节就好了。
#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
#include<stdio.h>
#include<vector>
#include<stack>
using namespace std;
//???????????
vector<int> G[2200];
bool vis[2200];
int scc[2200];
int dfs_clock=0;
int scc_cnt=0;
stack<int> stk;
int DFN[2200];
int low[2200];
int n,m;
char input[30];
void init()
{
dfs_clock=0;
scc_cnt=0;
for(int i=0;i<2200;i++)
{
G[i].clear();
vis[i]=0;
scc[i]=0;
DFN[i]=0;
low[i]=0;
}
}
int dfs(int now,int fa)
{
vis[now]=1;
DFN[now]=low[now]=++dfs_clock;
int size=G[now].size();
stk.push(now);
for(int i=0;i<size;i++)
{
int v=G[now][i];
if(vis[v]==0)
{
low[now]=min(low[now],dfs(v,now));
}
else if(scc[v]==0)
{
low[now]=min(low[now],DFN[v]);
}
}
if(DFN[now]==low[now])
{
scc_cnt++;
int x=-1;
do
{
x=stk.top();
stk.pop();
scc[x]=scc_cnt;
}while(x!=now);
}
return low[now];
}
int main()
{
while(cin>>n>>m)
{
init();
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
scanf("%s",input);
a=2*a;
b=2*b;
if(strcmp(input,"AND")==0)
{
if(c==1)
{
G[a^1].push_back(a);
G[b^1].push_back(b);
}
else
{
G[a].push_back(b^1);
G[b].push_back(a^1);
}
}
if(strcmp(input,"OR")==0)
{
if(c==1)
{
G[a^1].push_back(b);
G[b^1].push_back(a);
}
else
{
G[a].push_back(a^1);
G[b].push_back(b^1);
}
}
if(strcmp(input,"XOR")==0)
{
if(c==1)
{
G[a].push_back(b^1);
G[b].push_back(a^1);
G[a^1].push_back(b);
G[b^1].push_back(a);
}
else
{
G[a].push_back(b);
G[b].push_back(a);
G[a^1].push_back(b^1);
G[b^1].push_back(a^1);
}
}
}
for(int i=0;i<2*n;i++)
{
if(vis[i]==0) dfs(i,-1);
}
bool judge=true;
for(int i=0;i<2*n;i+=2)
{
if(scc[i]==scc[i+1])
{
judge=false;
break;
}
}
if(judge==false)
{
printf("NO\n");
}
else printf("YES\n");
}
return 0;
}