题意
传送门 POJ 3678
题解
o
p
=
A
N
D
op=AND
op=AND 时,有
{
¬
a
∨
¬
b
=
1
c
=
0
a
=
1
,
b
=
1
c
=
1
\begin{cases} \lnot a\lor \lnot b =1 & c=0\\ a=1,b=1 & c=1\\ \end{cases}
{¬a∨¬b=1a=1,b=1c=0c=1
o
p
=
O
R
op=OR
op=OR 时,有
{
¬
a
=
1
,
¬
b
=
1
c
=
0
a
∨
b
=
1
c
=
1
\begin{cases} \lnot a=1,\lnot b=1 & c=0\\ a\lor b =1 & c=1\\ \end{cases}
{¬a=1,¬b=1a∨b=1c=0c=1
o
p
=
X
O
R
op=XOR
op=XOR 时,有
{
(
a
∨
¬
b
)
∧
(
¬
a
∨
b
)
c
=
0
(
a
∨
b
)
∧
(
¬
a
∨
¬
b
)
c
=
1
\begin{cases} (a\lor \lnot b)\land (\lnot a\lor b) & c=0\\ (a\lor b)\land (\lnot a\lor \lnot b) & c=1\\ \end{cases}
{(a∨¬b)∧(¬a∨b)(a∨b)∧(¬a∨¬b)c=0c=1
利用蕴含
⇒
\Rightarrow
⇒ 将子句写成等价形式(如
a
∨
b
a\lor b
a∨b 改写为
¬
a
⇒
b
∧
¬
b
⇒
a
\lnot a \Rightarrow b \land \lnot b \Rightarrow a
¬a⇒b∧¬b⇒a;
a
=
1
a=1
a=1 改写为
¬
a
⇒
a
\lnot a\Rightarrow a
¬a⇒a),对每个布尔变量构造两个顶点分别代表
x
x
x 和
¬
x
\lnot x
¬x,以蕴含关系为边建立有向图,求解
2
−
S
A
T
2-SAT
2−SAT 问题即可。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define maxn 2005
int n, m, cmp[maxn];
bool used[maxn];
vector<int> G[maxn], rG[maxn], vs;
void add_edge(int u, int v)
{
G[u].push_back(v);
rG[v].push_back(u);
}
void dfs(int v)
{
used[v] = 1;
for (int i = 0; i < G[v].size(); i++)
{
int u = G[v][i];
if (!used[u])
{
dfs(u);
}
}
vs.push_back(v);
}
void rdfs(int v, int k)
{
used[v] = 1, cmp[v] = k;
for (int i = 0; i < rG[v].size(); i++)
{
int u = rG[v][i];
if (!used[u])
{
rdfs(u, k);
}
}
}
int scc(int n)
{
memset(used, 0, sizeof(used));
for (int v = 0; v < n; v++)
{
if (!used[v])
{
dfs(v);
}
}
memset(used, 0, sizeof(used));
int k = 0;
for (int i = vs.size() - 1; i >= 0; i--)
{
int v = vs[i];
if (!used[v])
{
rdfs(v, k++);
}
}
return k;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++)
{
int a, b, c;
char op[5];
scanf("%d%d%d %s", &a, &b, &c, op);
if (op[0] == 'A')
{
if (!c)
{
add_edge(a, n + b);
add_edge(b, n + a);
}
else
{
add_edge(n + a, a);
add_edge(n + b, b);
}
}
else if (op[0] == 'O')
{
if (!c)
{
add_edge(a, n + a);
add_edge(b, n + b);
}
else
{
add_edge(n + a, b);
add_edge(n + b, a);
}
}
else if (op[0] == 'X')
{
if (!c)
{
add_edge(n + a, n + b);
add_edge(b, a);
add_edge(a, b);
add_edge(n + b, n + a);
}
else
{
add_edge(a, n + b);
add_edge(b, n + a);
add_edge(n + a, b);
add_edge(b, n + a);
}
}
}
scc(2 * n);
bool f = 1;
for (int v = 0; v < n; v++)
{
if (cmp[v] == cmp[n + v])
{
f = 0;
break;
}
}
puts(f ? "YES" : "NO");
return 0;
}