poj 3678 2-sat(强连通)

题目链接 poj 3678
Katu Puzzle
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 8340   Accepted: 3077

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.
这是我的第一道2-sat题,参考璇神思路和代码,终于ac了。
将一个点拆分成X(2*i)与非X(2*i+1)两点,然后按照与,或,异或的运算规则,推出每一组运算对象的充分条件并建边。跑一遍强连通,判断每一组x与非x是否在同一个强连通分量中,如果是,则输出no,否则输出yes。理由是:如果一个点可以取两种状态(0,1),这显然(请原谅我用这个不礼貌的词)不合题意
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <stack>
#include <sstream>
#include <cmath>
#include <queue>
#include <string>
#include <vector>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#include<bits/stdc++.h>
#define zeros(a) memset(a,0,sizeof(a))
#define ones(a) memset(a,-1,sizeof(a))
#define lson step<<1
#define rson lson+1
#define esp 1e-6
#define oo 0x3fffffff
#define TEST cout<<"*************************"<<endl;

using namespace std;
typedef long long ll;
const int maxn=2000+10;
const int maxm=1000000+10;
struct side
{
    int v,next;
}e[maxm<<2];
int dfn[maxn],head[maxn],low[maxn],belong[maxn],s[maxn],in_s[maxn];
int T,tot,top,index;
int n,m;
char str[5];
inline int Min(int a,int b)
{
    return a<b?a:b;
}
void build(int u,int v)
{
    e[T].v=v;
    e[T].next=head[u];
    head[u]=T++;
}
void init()
{
    ones(head);
    zeros(belong);
    zeros(low);
    ones(dfn);
    zeros(s);
    zeros(in_s);
    index=top=T=0;
    tot=1;
}
void tarjan(int u)
{
    dfn[u]=low[u]=tot++;
    in_s[u]=1;
    s[++top]=u;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].v;
        if(dfn[v]==-1)
        {
            tarjan(v);
            low[u]=Min(low[v],low[u]);
        }
        else if(in_s[v])
            low[u]=Min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        index++;
        int temp;
        do
        {
            temp=s[top--];
            in_s[temp]=0;
            belong[temp]=index;
        }while(temp!=u);
     }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int T_T;
    //scanf("%d",T_T);
    while(~scanf("%d%d",&n,&m))
    {
        init();
        int a,b,c;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d%s",&a,&b,&c,str);
            if(str[0]=='A')
            {
                if(c==1)
                {
                    build(2*a,2*a+1);
                    build(2*b,2*b+1);
                }
                else
                {
                    build(2*a+1,2*b);
                    build(2*b+1,2*a);
                }
            }
            else if(str[0]=='O')
            {
                if(c==0)
                {
                    build(2*a+1,2*a);
                    build(2*b+1,2*b);
                }
                else
                {
                    build(2*a,2*b+1);
                    build(2*b,2*a+1);
                }
            }
            else
            {
                if(c==1)
                {
                    build(2*a+1,2*b);
                    build(2*b,2*a+1);
                    build(2*b+1,2*a);
                    build(2*a,2*b+1);
                }
                else
                {
                    build(2*a,2*b);
                    build(2*b,2*a);
                    build(2*a+1,2*b+1);
                    build(2*b+1,2*a+1);
                }
            }
        }
        for(int i=0;i<2*n;i++)
        {
            if(dfn[i]==-1)
            {
                tarjan(i);
            }
        }
        int flag=1;
        for(int i=0;i<n;i++)
        {
            if(belong[2*i]==belong[2*i+1])
            {
                flag=0;
                break;
            }
        }
        if(flag)
            printf("YES
");
        else
            printf("NO
");
    }
    return 0;
}
不为失败找借口,只为成功找方法
原文地址:https://www.cnblogs.com/youmi/p/4533384.html