题解:P10969 Katu Puzzle
思路
前置芝士:P4782 【模板】2-SAT
将每个点拆为「TRUE」和「FALSE」两个点。
题目给出了
即如果有矛盾,则让有矛盾的两个状态,分别向另一个状态的“非”连一条边,通俗的来讲就是:
这也是很多 2-SAT 题用的连边方法,可以学习一下。
这时候又有人问了:驻波驻波,那如果我是
这种情况即为
我们考虑我们是如何确定一个点的值,我们比较
然后依照题目的要求进行建边,具体如何建边这里就不再赘述了,这种东西还是要自己想一想的。
最后再判断一下
AC code
#include<bits/stdc++.h>
using namespace std;
#define N 2005
int n, m;
vector<int> g[N];
int val(int x, int s) {
if (s == 0) return x + n;
return x;
}
int cnt, dfn[N], low[N], buc[N], scc[N], num;
stack<int> stk;
void Tarjan(int u) {
dfn[u] = low[u] = ++cnt;
stk.push(u);
buc[u] = 1;
for (auto v : g[u]) {
if (!dfn[v]) {
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (buc[v])
low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
int y;
num++;
do {
y = stk.top();
stk.pop();
buc[y] = 0;
scc[y] = num;
} while (y != u);
}
}
signed main() {
cin >> n >> m;
while (m--) {
int a, b, c;
string op;
cin >> a >> b >> c >> op;
a++;
b++;
if (op == "AND") {
if (c) {
g[val(a, 0)].push_back(val(a, 1));
g[val(b, 0)].push_back(val(b, 1));
}
else {
g[val(a, 1)].push_back(val(b, 0));
g[val(b, 1)].push_back(val(a, 0));
}
}
if (op == "OR") {
if (c) {
g[val(a, 0)].push_back(val(b, 1));
g[val(b, 0)].push_back(val(a, 1));
}
else {
g[val(a, 1)].push_back(val(a, 0));
g[val(b, 1)].push_back(val(b, 0));
}
}
if (op == "XOR") {
if (c) {
g[val(a, 1)].push_back(val(b, 0));
g[val(b, 1)].push_back(val(a, 0));
g[val(a, 0)].push_back(val(b, 1));
g[val(b, 0)].push_back(val(a, 1));
}
else {
g[val(a, 1)].push_back(val(b, 1));
g[val(b, 1)].push_back(val(a, 1));
g[val(a, 0)].push_back(val(b, 0));
g[val(b, 0)].push_back(val(a, 0));
}
}
}
for (int i = 1; i <= 2 * n; i++)
if (!dfn[i]) Tarjan(i);
for (int i = 1; i <= n; i++) {
if (scc[val(i, 0)] == scc[val(i, 1)]) {
cout << "NO";
return 0;
}
}
cout << "YES";
return 0;
}