Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 7395 | Accepted: 2720 |
Description
Katu Puzzle is presented as a directed graph G(V, E) with each edge e(a, b) labeled by a boolean operator op (one of AND, OR, XOR) and an integer c (0 ≤ c ≤ 1). One Katu is solvable if one can find each vertex Vi a value Xi (0 ≤ Xi ≤ 1) such that for each edge e(a, b) labeled by op and c, the following formula holds:
Xa op Xb = c
The calculating rules are:
|
|
|
Given a Katu Puzzle, your task is to determine whether it is solvable.
Input
The first line contains two integers N (1 ≤ N ≤ 1000) and M,(0 ≤ M ≤ 1,000,000) indicating the number of vertices and edges.
The following M lines contain three integers a (0 ≤ a < N), b(0 ≤ b < N), c and an operator op each, describing the edges.
Output
Output a line containing "YES" or "NO".
Sample Input
4 4 0 1 1 AND 1 2 1 OR 3 2 0 AND 3 0 0 XOR
Sample Output
YES
Hint
题意:
给出 N (1 ~ 1000)和 M (0 ~ 1000000),代表有 N 个命题,M 条关系式。后给出 M 条关系式是什么。问能否找到一组命题的解,满足所有的关系式。
思路:
2 - sat。根据给出的关系式,将可以确定的关系进行建图。比如 a & b = 1,则 a == 1 -> b == 1,b == 1 -> a == 1,若 a == 0 或者 b == 0,则无论如何都不可能满足条件式,所以要把矛盾的条件也要进行建图,建图方法为 a == 0 -> a== 1,b == 0 -> b == 1。对 | 的情况也是如此,对于 ^ 则没有矛盾的情况。建图后判断一个命题的真和假有没有在同一个强连通分量即可。并且用 STL 的 vector 容器存邻接表。
AC:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
#include <vector>
using namespace std;
const int NMAX = 1005 * 2;
const int EMAX = 1000000 * 2;
int n, m;
vector<int> v[NMAX];
int dfs_clock, scc_cnt;
int pre[NMAX], low[NMAX], cmp[NMAX];
stack<int> s;
void dfs(int u) {
pre[u] = low[u] = ++dfs_clock;
s.push(u);
for (int i = 0; i < v[u].size(); ++i) {
if (!pre[ v[u][i] ]) {
dfs( v[u][i] );
low[u] = min(low[u], low[ v[u][i] ]);
} else if (!cmp[ v[u][i] ]) {
low[u] = min(low[u], pre[ v[u][i] ]);
}
}
if (low[u] == pre[u]) {
++scc_cnt;
for (;;) {
int x = s.top(); s.pop();
cmp[x] = scc_cnt;
if (x == u) break;
}
}
}
void scc() {
dfs_clock = scc_cnt = 0;
memset(pre, 0, sizeof(pre));
memset(cmp, 0, sizeof(cmp));
for (int u = 0; u < 2 * n; ++u) {
if (!pre[u]) dfs(u);
}
}
void add_edge (int a, int b, int ans, char *res) {
if (!strcmp(res, "AND")) {
if (!ans) {
v[a].push_back(n + b);
v[b].push_back(n + a);
} else {
v[a].push_back(b);
v[b].push_back(a);
v[n + a].push_back(a); //矛盾情况
v[n + b].push_back(b); //矛盾情况
}
} else if (!strcmp(res, "OR")) {
if (!ans) {
v[n + a].push_back(n + b);
v[n + b].push_back(n + a);
v[a].push_back(n + a); //矛盾情况
v[b].push_back(n + b); //矛盾情况
} else {
v[n + a].push_back(b);
v[n + b].push_back(a);
}
} else if (!strcmp(res, "XOR")) {
if (!ans) {
v[a].push_back(b);
v[b].push_back(a);
v[n + a].push_back(n + b);
v[n + b].push_back(n + a);
} else {
v[a].push_back(n + b);
v[b].push_back(n + a);
v[n + a].push_back(b);
v[n + b].push_back(a);
}
}
}
int main() {
scanf("%d%d", &n, &m);
while (m--) {
int a, b, ans;
char res[5];
scanf("%d%d%d%s", &a, &b, &ans, res);
add_edge(a, b, ans, res);
}
scc();
for (int i = 0; i < n; ++i) {
if (cmp[i] == cmp[n + i]) {
printf("NO\n");
return 0;
}
}
printf("YES\n");
return 0;
}