POJ 3678

时间:2022-02-04 04:42:44
Katu Puzzle
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 7391   Accepted: 2717

Description

Katu Puzzle is presented as a directed graph G(VE) 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 ≤ X≤ 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:

AND 0 1
0 0 0
1 0 1
OR 0 1
0 0 1
1 1 1
XOR 0 1
0 0 1
1 1 0

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 (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

X0 = 1, X1 = 1, X2 = 0, X3 = 1.

Source

2-sat 
 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack> using namespace std; const int MAX_N = ;
const int edge = 1e6 + ;
int first[ * MAX_N],Next[ * edge],v[ * edge];
int N,M,dfs_clock,scc_cnt;
int low[ * MAX_N],pre[ * MAX_N],cmp[ * MAX_N];
stack<int > S; void dfs(int u) {
low[u] = pre[u] = ++dfs_clock;
S.push(u);
for(int e = first[u]; e != -; e = Next[e]) {
if(!pre[ v[e] ]) {
dfs(v[e]);
low[u] = min(low[u],low[ v[e] ]);
} else {
if(!cmp[ v[e] ]) {
low[u] = min(low[u],pre[ v[e] ]);
}
}
} if(pre[u] == low[u]) {
++scc_cnt;
for(;;) {
int x = S.top(); S.pop();
cmp[x] = scc_cnt;
if(x == u) break;
}
}
} void scc() {
dfs_clock = scc_cnt = ;
memset(cmp,,sizeof(cmp));
memset(pre,,sizeof(pre)); for(int i = ; i < * N; ++i) if(!pre[i]) dfs(i);
} void add_edge(int id,int u) {
int e = first[u];
Next[id] = e;
first[u] = id;
} bool solve() {
scc();
for(int i = ; i < N; ++i) {
if(cmp[i] == cmp[N + i]) return false;
}
return true;
} void build(int a,int b,int c,char ch[],int &len) {
if(strcmp(ch,"AND") == ) {
if(c == ) {
v[len] = b;
add_edge(len++,a + N);
v[len] = a;
add_edge(len++,b + N);
} else {
v[len] = b + N;
add_edge(len++,a + N);
v[len] = a + N;
add_edge(len++,b + N);
v[len] = a + N;
add_edge(len++,a);
v[len] = b + N;
add_edge(len++,b);
}
}
if(strcmp(ch,"OR") == ) {
if(c == ) {
v[len] = b;
add_edge(len++,a);
v[len] = b;
add_edge(len++,b + N);
v[len] = a;
add_edge(len++,b);
v[len] = a;
add_edge(len++,a + N);
} else {
v[len] = b + N;
add_edge(len++,a);
v[len] = a + N;
add_edge(len++,b);
}
}
if(strcmp(ch,"XOR") == ) {
if(c == ) {
v[len] = b;
add_edge(len++,a);
v[len] = a + N;
add_edge(len++,b + N);
v[len] = a;
add_edge(len++,b);
v[len] = b + N;
add_edge(len++,a + N);
} else {
v[len] = b + N;
add_edge(len++,a);
v[len] = a + N;
add_edge(len++,b);
v[len] = b;
add_edge(len++,a + N);
v[len] = a;
add_edge(len++,b + N);
}
} } int main()
{
//freopen("sw.in","r",stdin);
scanf("%d%d",&N,&M);
for(int i = ; i < * N; ++i) first[i] = -;
int len = ;
for(int i = ; i <= M; ++i) {
int a,b,c;
char ch[];
scanf("%d%d%d%s",&a,&b,&c,ch);
build(a,b,c,ch,len); } printf("%s\n",solve() ? "YES" : "NO");
//cout << "Hello world!" << endl;
return ;
}