poj 3678 Katu Puzzle 【2-sat 经典建图】

来源:互联网 发布:linux如何给文件夹改名 编辑:程序博客网 时间:2024/06/06 14:25
Katu Puzzle
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 8469 Accepted: 3135

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:

AND01000101OR01001111XOR01001110

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 40 1 1 AND1 2 1 OR3 2 0 AND3 0 0 XOR

Sample Output

YES

Hint

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


题意:给出N个布尔变量,每个变量要么真要么假。现在给出M个关系,问你是否存在一组解满足所有条件。


思路:


一:对于AND 

1,c == 1时,则a和b全为真,建边 !a -> a 和 !b -> b;

2,c == 0时,则a和b至少一个为假,建边 a -> !b 和 b -> !a;

二:对于OR

1,c == 1时,则a和b至少一个为真,建边!a -> b 和 !b -> a;

2,c == 0时,则a和b全为假,建边a -> !a 和 b -> !b;

三:对于XOD

1,c == 1时,则a和b不同,建边!a -> b 、!b -> a、a -> !b 、 b -> !a;

2,c == 0时,则a和b相同,建边a -> b 、b -> a、!a -> !b 、 !b -> !a;


建好图,tarjan求SCC 判断是否矛盾即可。


AC代码:


#include <cstdio>#include <cstring>#include <queue>#include <vector>#include <stack>#include <algorithm>#define MAXN 2000+10#define MAXM 400000#define INF 1000000using namespace std;vector<int> G[MAXN];int low[MAXN], dfn[MAXN];int dfs_clock;int sccno[MAXN], scc_cnt;stack<int> S;bool Instack[MAXN];int N, M;void init(){for(int i = 0; i < 2*N; i++) G[i].clear();}void getMap(){int a, b, c;char op[10];while(M--){scanf("%d%d%d%s", &a, &b, &c, op);switch(op[0]){case 'A': if(c == 1)//a,b取1 {G[a + N].push_back(a);G[b + N].push_back(b);}else//a,b至少一个不为真 {G[a].push_back(b + N);G[b].push_back(a + N);}break;case 'O':if(c == 1)//a,b最少有一个为真 {G[b + N].push_back(a);G[a + N].push_back(b);}else//a,b都为假 {G[a].push_back(a + N);G[b].push_back(b + N);}break;case 'X':if(c == 1)//a b 不同值 {G[a + N].push_back(b);G[a].push_back(b + N);G[b].push_back(a + N);G[b + N].push_back(a);}else//a b 同真同假 {G[a].push_back(b);G[b].push_back(a);G[a + N].push_back(b + N);G[b + N].push_back(a + N);}}}}void tarjan(int u, int fa){int v;low[u] = dfn[u] = ++dfs_clock;S.push(u);Instack[u] = true;for(int i = 0; i < G[u].size(); i++){v = G[u][i];if(!dfn[v]){tarjan(v, u);low[u] = min(low[u], low[v]);}else if(Instack[v])low[u] = min(low[u], dfn[v]);}if(low[u] == dfn[u]){scc_cnt++;for(;;){v = S.top(); S.pop();Instack[v] = false;sccno[v] = scc_cnt;if(v == u) break; }}}void find_cut(int l, int r){memset(low, 0, sizeof(low));memset(dfn, 0, sizeof(dfn));memset(sccno, 0, sizeof(sccno));memset(Instack, false, sizeof(Instack));dfs_clock = scc_cnt = 0;for(int i = l; i <= r; i++)if(!dfn[i]) tarjan(i, -1);}void solve(){for(int i = 0; i < N; i++){if(sccno[i] == sccno[i + N]){printf("NO\n");return ;}}printf("YES\n");}int main(){while(scanf("%d%d", &N, &M) != EOF){init();getMap();find_cut(0, 2*N-1);solve();}return 0;}


0 0