poj3678 2-sat

Katu Puzzle
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 8335   Accepted: 3073

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

X 0 = 1,  X 1 = 1,  X 2 = 0,  X 3 = 1.

题意:有n个点,每两个点可以通过三种运算符得到这两点之间的边边权。

分析:每个点有两种可选的状态0或1,显然这是2-sat 问题,现在就是建图了。

注意:

 1、AND:  a AND b=1,说明a和b必须是1,为了找出矛盾,那么就让a和b选0的时候无解,所以连接 a->a+n,b->b+n,也是为了建反边后,top序先选择a,b。

 2、有些边不能建双向边,比如i&j=0,只能说明如果a为1,b必须为0,不能说明如果b为0,a 必须为1,还可以为0.

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define MAX 1005
#define mod 10000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
struct edge {
    int v,next;
}e[MAX*MAX];
int tot,head[MAX];
void addedge(int u,int v) {
    e[tot].v=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
int tarjan_clock=0,scc_cnt=0;
int pre[MAX],sccno[MAX],lowlink[MAX];
stack<int> sk;
void Tarjan(int u) {
    pre[u]=lowlink[u]=++tarjan_clock;
    sk.push(u);
    for(int i=head[u]; i!=-1; i=e[i].next) {
        int v=e[i].v;
        if(!pre[v]) {
            Tarjan(v);
            lowlink[u]=min(lowlink[u],lowlink[v]);
        } else if(!sccno[v])
            lowlink[u]=min(lowlink[u],pre[v]);
    }
    if(lowlink[u]==pre[u]) {
        scc_cnt++;
        while(1) {
            int x=sk.top();
            sk.pop();
            sccno[x]=scc_cnt;
            if(x==u)
                break;
        }
    }
}
void find_scc(int n) {
    tarjan_clock=scc_cnt=0;
    CLR(sccno,0);
    CLR(pre,0);
    for(int i=1; i<=n; i++) {
        if(!pre[i]) Tarjan(i);
    }
}
void init() {
    tot=0;
    CLR(head,-1);
}
int main() {
    int n,m,u,v,w;
    char s[10];
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) {
        scanf("%d%d%d %s",&u,&v,&w,s);
        u++,v++;
        if(s[0]=='A') {
            if(w) {
                addedge(u+n,v+n);
                addedge(v+n,u+n);
                addedge(u,u+n);
                addedge(v,v+n);
            }
            else {
                addedge(u+n,v);
                addedge(v+n,u);
            }
        } else if(s[0]=='O') {
            if(w) {
                addedge(u,v+n);
                addedge(v,u+n);
            } else {
                addedge(u+n,u);
                addedge(v+n,v);
                addedge(u,v);
                addedge(v,u);
            }
        }else {
            if(w) {
                addedge(u,v+n);
                addedge(v,u+n);
                addedge(u+n,v);
                addedge(v+n,u);
            } else {
                addedge(u,v);
                addedge(v,u);
                addedge(u+n,v+n);
                addedge(v+n,u+n);
            }
        }
    }
    find_scc(2*n);
    for(int i=1;i<=n;i++)
        if(sccno[i]==sccno[i+n]) {
            printf("NO\n");
            return 0;
        }
    printf("YES\n");
    return 0;
}


你可能感兴趣的:(2-sat)