#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 2e5 + 10;
int n, m, a, b, c;
char s[100];
int DFN[maxn], vis[maxn], low[maxn], Stack[maxn * 10], Belong[maxn], top, tol, cnt;
vector<int> e[maxn];
void Tarjan(int u)
{
DFN[u] = low[u] = ++tol;
vis[u] = true;
Stack[++top] = u;
int l = e[u].size();
for (int i = 0; i < l; i++)
{
int v = e[u][i];
if (!DFN[v])
{
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (vis[v] && DFN[v] < low[u]) low[u] = DFN[v];
}
if (DFN[u] == low[u])
{
cnt++; int v;
do
{
v = Stack[top--];
vis[v] = false;
Belong[v] = cnt;
}
while (v != u);
}
}
bool TwoSat(int n)
{
for (int i = 0; i < 2 * n; i++)
if (!DFN[i]) Tarjan(i);
for (int i = 0; i < n; i++)
if (Belong[2 * i] == Belong[2 * i + 1]) return false;
return true;
}
int main(int argc, char const *argv[])
{
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++)
{
scanf("%d%d%d%s", &a, &b, &c, s);
if (s[0] == 'A')
{
if (c)
{
e[2 * a + 1].push_back(2 * a);
e[2 * b + 1].push_back(2 * b);
}
else
{
e[2 * a].push_back(2 * b + 1);
e[2 * b].push_back(2 * a + 1);
}
}
else if (s[0] == 'O')
{
if (c)
{
e[2 * a + 1].push_back(2 * b);
e[2 * b + 1].push_back(2 * a);
}
else
{
e[2 * a].push_back(2 * a + 1);
e[2 * b].push_back(2 * b + 1);
}
}
}
printf("%s\n", (TwoSat(n) ? "YES" : "NO"));
return 0;
}
有一个有向图G(V,E),每条边e(a,b)上有一个位运算符op(AND, OR或XOR)和一个值c(0或1)。
问能不能在这个图上的每个点分配一个值X(0或1),使得每一条边e(a,b)满足 Xa op Xb = c
对于两个点a和 b, a有两个值a1=0,a2=1, b也有两个值 b1=0, b2=1.
那么枚举这两点的所有关系(a1, b1)(a1, b2)(a2, b1)(a2, b2)
然后根据位运算符看每个关系时符合条件还是不符合,如果不符合就说明这个关系时矛盾对,要添加两条边
假设是关系(a1,b1)矛盾,那么就要添加边 a1—>b2, b1—>a2即可。