思路:
2-SAT模板题,注意建边。
假设有点 i1 , j1, i2, j2
当只能选 i1 和 j1 点时,这样加边:
addedge(i1,j1),addedge(j1,i1);
addedge(i2,i1),addedge(j2,j1);//构造这组边为了使选i2,j2非法,因为只能选i1和j1
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
#include <queue>
using namespace std;
const int maxn = 2200;
struct edge{
int from,to,v,next;
}ed[6010000];
int head[maxn];
int cnte;
void ae(int x,int y){
ed[++cnte].to = y;
ed[cnte].next = head[x];
head[x]=cnte;
}
int dfn[maxn],low[maxn],vis[maxn],stak[maxn],belong[maxn],cntc,cnts,index;//strong connected component //cnt of stack
void dfs(int u){
dfn[u]=low[u] = ++index;
stak[cnts++]=u;
vis[u]=1;
for(int i = head[u];i!=-1;i=ed[i].next){
int v = ed[i].to;
if(!dfn[v]){
dfs(v);
low[u] = min(low[u],low[v]);
}
else if(vis[v]){
low[u] = min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
cntc++;int v;
do{
v = stak[--cnts];
vis[v] = 0;
belong[v] = cntc;
}while(v!=u);
}
}
int n,m;
void tarjan(){
for(int i = 1;i <= 2*n;i++){
if(!dfn[i]){
dfs(i);
}
}
}
char s[20];
int main(){
scanf("%d%d",&n,&m);
int a,b,c;
memset(head,-1,sizeof(head));
for(int i = 1;i <= m;i++){
scanf("%d%d%d%s",&a,&b,&c,s);
a++;b++;
if(s[0] == 'A'){
if(c == 1){
ae(a+n,a);ae(b+n,b);
ae(a,b);ae(b,a);
}
else{
ae(a,b+n);ae(b,a+n);
}
}
else if(s[0] == 'O'){
if(c == 1){
ae(a+n,b);ae(b+n,a);
}
else{
ae(a,a+n);ae(b,b+n);
ae(a+n,b+n);ae(b+n,a+n);
}
}
else if(s[0] == 'X'){
if(c == 1){
ae(a,b+n);ae(b,a+n);
ae(a+n,b);ae(b+n,a);
}
else{
ae(a,b);ae(b,a);
ae(a+n,b+n);ae(b+n,a+n);
}
}
}
tarjan();
int flag = 1;
for(int i = 1;i <= n;i++){
if(belong[i] == belong[i+n]){
flag = 0;break;
}
}
if(flag == 1){
puts("YES");
}
else
puts("NO");
return 0;
}