1. 程式人生 > >poj3678 Katu Puzzle

poj3678 Katu Puzzle

sent rul stream direct with rule search blog ive

Katu Puzzle
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 10239 Accepted: 3823

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:

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

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

Source

POJ Founder Monthly Contest – 2008.07.27, Dagger. 分析:每個數可以取0也可以取1,那麽就是2-SAT問題!2-SAT問題最重要的就是建邊,建邊的關鍵是“必須”,也就是說,當a時,必須b,才從a連邊到b,這道題涉及到自己到自己的反節點的連邊,具體看代碼:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <stack>

using namespace std;

const int maxn = 1010 * 3,maxm = 2000010;

int n,m,head[maxn],top,to[maxm],nextt[maxm],tot = 1,dfs_clock,pre[maxn],low[maxn],scc[maxn];

stack <int> s;

void add(int x,int y)
{
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;    
} 

void tarjan(int u)
{
    pre[u] = low[u] = ++dfs_clock;
    s.push(u);
    for (int i = head[u];i; i = nextt[i])
    {
        int v = to[i];
        if (!pre[v])
        {
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else
        if (!scc[v])
        low[u] = min(low[u],pre[v]);
    }
    if (pre[u] == low[u])
    {
        top++;
        while (1)
        {
            int t = s.top();
            s.pop();
            scc[t] = top;
            if (t == u)
            break;
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= m; i++)
    {
        int a,b,c;
        char op[5];
        scanf("%d%d%d",&a,&b,&c);
        scanf("%s",op);
        if (op[0] == A) //and
        {
            if (c == 1)
            {
                add(a + n,b + n);
                add(b + n,a + n);
                add(a,a + n); //a如果為0顯然不能滿足要求,所以a必須為1,所以從0連向1
                add(b,b + n);
            }
            else
            {
                add(a + n,b);
                add(b + n,a);
            }
        }
        if (op[0] == X)
        {
            if (c == 1)
            {
                add(a,b + n);
                add(a + n,b);
                add(b, a + n);
                add(b + n,a);
            }
            else
            {
                add(a,b);
                add(b,a);
                add(a + n,b + n);
                add(b + n,a + n);
            }
        }
        if (op[0] == O)
        {
            if (c == 1)
            {
                add(a,b + n);
                add(b,a + n);
            }
            else
            {
                add(a,b);
                add(b,a);
                add(a + n,a); //a,b必須全都為0才可以,選1後我們強行讓它選0.
                add(b + n,b);
            }
        }
    }
    for (int i = 0; i <= 2 * n - 1; i++)
    if (!pre[i])
    tarjan(i);
    for (int i = 0; i < n; i++)
    if (scc[i] == scc[i + n])
    {
        printf("NO\n");
        return 0;
    } 
    printf("YES\n");
     
    return 0;
}

poj3678 Katu Puzzle