看这个题的时候让我明白了前面博客中一个不明白的地方,一个关于2-Sat建边的问题,我们在2-Sat建边是,我们所建的边是要求选这个点,那么这个点之后的带你也是一定被选的,比如我们说A和B都是可以去0或1,他们满足A AND B = 1,那么A和B就必须都是1了,我们要怎么表示这个条件呢?我们要连接 A0 -> A1,B0 -> B1,这样我们如果选0的话,我们就必须要选1,那么他两个就一定不满足2-Sat的答案,所以只能选择1....
我们看一下这个题:
A AND B = 1 添加条件:A0 -> A1 , B0 -> B1
A AND B = 0 ,那么满足A为1时,B就一定要选0,相反B选1是,A一定选0 所以添加两个条件 : A1 -> B0 , B1 -> A0
A OR B = 1 , 它满足A = 0,B一定为 1,相反B= 0,A一定为1:A0 -> B1 , B0 -> A1
A OR B = 0 ,满足连个都是0,这个和第一个相似,我们要添加条件:A1 -> A0, B1 -> B0
A XOR B = 0,也就是两个必须是相同的,那么满足:A0 -> B0 , A1 -> B1 , B0 -> A0, B1 -> A1
A XOR B = 1,也就是两个元素都是不行同的,满足:A0 -> B1 , A1 -> B0 , B1 -> A0, B0 -> A1
那么程序就剩下2-Sat判断可行性问题了:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 4000000;
const int MAXM = 2505;
int n,m;
char str[5];
struct Edge{
int u,v,next;
}edge[MAXN];
int head[MAXM],k;
int dfn[MAXM],low[MAXM],stact[MAXM],vis[MAXM],index,num,tot,belong[MAXM];
void Init()
{
k = 0;index = 0;num =0 ;tot = 0;
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(stact,0,sizeof(stact));
memset(vis,0,sizeof(vis));
memset(belong,0,sizeof(belong));
}
void Add_edge(int u,int v)
{
edge[k++].u = u;edge[k].v = v;edge[k].next = head[u];head[u] = k;
}
void Tarjan(int u)
{
dfn[u] = low[u] = ++tot;
stact[++index] = u;vis[u] = 1;
for(int k = head[u];k != -1 ;k = edge[k].next)
{
int v = edge[k].v;
if(!dfn[v]){
Tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(vis[v])
low[u] = min(low[u],dfn[v]);
}
if(dfn[u] == low[u]){
num ++;
do{
int v = stact[index];
belong[v] = num;
vis[v] = 0;
index --;
}while(u != stact[index+1]);
}
}
int main()
{
Init();
scanf("%d%d",&n,&m);//i表示0,i+n表示1
int a,b,c;
for(int i =0 ;i < m;i ++)
{
scanf("%d%d%d%s",&a,&b,&c,str);
if(str[0] == 'A')
{
if(c == 1){//必须都是1的情况我们可以让i -> i+n这样选择0的话就必须选择1,那么我们就可以推出矛盾
Add_edge(a,a+n);Add_edge(b,b+n);
}else{//其中一个为0,
Add_edge(a+n,b);Add_edge(b+n,a);
}
}
if(str[0] == 'O')
{
if(c == 0) {//两个都为0
Add_edge(a+n,a);Add_edge(b+n,b);
}
else{//其中一个为 1
Add_edge(a,b+n);Add_edge(b,a+n);
}
}
if(str[0] == 'X'){
if(c == 0){//a和b相同,同时为0或者同时为1
Add_edge(a,b);Add_edge(b,a);Add_edge(a+n,b+n);Add_edge(b+n,a+n);
}
else{//a和b不同
Add_edge(a,b+n);Add_edge(b,a+n);Add_edge(a+n,b);Add_edge(b+n,a);
}
}
}
for(int i = 0;i < 2*n;i ++)
if(!dfn[i])
Tarjan(i);
for(int i = 0;i < n;i ++)
{
if(belong[i] == belong[i+n])
{
printf("NO\n");
return 0;
}
}
printf("YES\n");
}