因为A和B的取值只有0,1,在运算里就可以用2-SAT来解决。
建图过程如下:
1) X AND Y=1,Add(I',J'),Add(J',I'),Add(I,I'),Add(J,J')
2) X AND Y=0,Add(I',J),Add(J',I)
3) X OR Y=1,Add(I,J'),Add(J,I')
4) X OR Y=0,Add(I,J),Add(J,I),Add(I',I),Add(J',J)
5) X XOR Y=1,Add(I',J),Add(J',I),Add(I,J'),Add(J,I')
6) X XOR Y=0,Add(I',J'),Add(J',I'),Add(I,J),Add(J,I)
一开始我没理解红色部分的建图。后来我才知道,如果没有红色部分,那么有一部分的冲突就没有解决。比如:样例里同时有A OR B = 0, A OR B = 1。如果没有下面两句话,Add(I',I),Add(J',J),那么程序是判断不出冲突的,因为在建图的时候就只有A<->B,A -> B', B -> A'。A和A’,B和B‘并不在一个强连通分量里,所以无法判别冲突,画个图看一下就知道了。
对于红色部分更好的解释应该是:X OR Y的时候,X或Y任何一个不能为1,否则就会有冲突,因此从X'和Y'向X, Y连接一条边。
Code:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 2222;
const int maxm = 2222222;
struct node
{
int v, next;
}edge[maxm];
int head[maxn], k, n, m;
int low[maxn], dfn[maxn], belong[maxn], inde, cnt;
int stack[maxn << 2], top;
bool instack[maxn];
void add_edge(int u, int v)
{
edge[k].v = v, edge[k].next = head[u];
head[u] = k ++;
}
void tarjan(int u)
{
int v;
dfn[u] = low[u] = inde ++;
instack[u] = true;
stack[top ++] = u;
for(int i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v])
low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u])
{
cnt ++;
do{
v = stack[-- top];
instack[v] = false;
belong[v] = cnt;
num[cnt] ++;
}while(v != u);
}
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
memset(head, -1, sizeof(head));
k = 0;
while(m --)
{
int u, v, val;
char op[10];
scanf("%d%d%d%s", &u, &v, &val, op);
if(op[0] == 'A')
{
if(val == 0)
{
add_edge(u + n, v);
add_edge(v + n, u);
}
else
{
add_edge(u + n, v + n);
add_edge(v + n, u + n);
add_edge(u, u + n); // u can't be 0
add_edge(v, v + n); // v can't be 0
}
}
else if(op[0] == 'O')
{
if(val == 0)
{
add_edge(u, v);
add_edge(v, u);
add_edge(u + n, u); // u can't be 1
add_edge(v + n, v); // v can't be 1
}
else
{
add_edge(u, v + n);
add_edge(v, u + n);
}
}
else if(op[0] == 'X')
{
if(val == 0)
{
add_edge(u, v);
add_edge(v, u);
add_edge(u + n, v + n);
add_edge(v + n, u + n);
}
else
{
add_edge(u, v + n);
add_edge(v, u + n);
add_edge(v + n, u);
add_edge(u + n, v);
}
}
}
memset(dfn, 0, sizeof(dfn));
memset(instack, false, sizeof(instack));
top = 0, cnt = 0, inde = 1;
int nn = 2 * n;
for(int i = 0; i < nn; i ++)
if(!dfn[i])
tarjan(i);
bool ok = true;
for(int i = 0; i < nn; i ++)
if(belong[i] == belong[i + n])
ok = false;
if(!ok)
printf("NO\n");
else
printf("YES\n");
}
}