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\n");
        else
            printf("NO\n");
    }
    return 0;
}
时间: 2024-08-01 06:30:11

poj 3678 2-sat(强连通)的相关文章

poj 3678 2-sat

2-sat经典建图,注意AND为1的时候,a=0要和a=1连边,b同理,因为此时a,b都不能为0. OR为0时候,a=1要和a=0连边,b同理,因为此时a,b都不能为1. #include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<cmath> using namespace std; #defi

POJ 3678

这道题唯一一个注意的地方是,如出现X\/Y=0这种关系时,X=0,Y=0.已经是可以肯定的关系了,所以可以连边X->-X. 我也错了上面这地方.看来,还不够.以后要细心才好. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string.h> 5 #include <algorithm> 6 #include <cmath> 7

POJ 2186 Popular Cows --强连通分量

题意:给定一个有向图,问有多少个点由任意顶点出发都能达到. 分析:首先,在一个有向无环图中,能被所有点达到点,出度一定是0. 先求出所有的强连通分支,然后把每个强连通分支收缩成一个点,重新建图,这样,这个有向图就变成了一个有向无环图. 在这个新的图中,只需知道出度为0的点有几个即可. 如果出度为0的点超过1个,则输出0:否则输出出度为0的点所代表的那个强连通分支的分量数即可. 用Tarjan求强连通分量 代码: #include <iostream> #include <cstdio&g

POJ 3678 Katu Puzzle(强连通 法)

题目链接 题意:给出a, b, c 和操作类型 (与或异或),问是否满足所有的式子 主要是建图: 对于 and , c == 1: 说明 a 和 b都是1,那么 0 就不能取, a' -> a , b' - > b ,因为 a 和 a'是对立事件,对于 a' - >a说明,a'如果成立,那么a也一定存在,显然这是不可能的所以a'不会 成立的. c == 0 说明 a 和 b不全为1, a' -> b , b' -> a 对于 or,  c == 1 :说明 a 和 b 不全为

POJ 3678 Katu Puzzle(2-sat 模板题)

题目链接:http://poj.org/problem?id=3678 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

POJ 3177 Redundant Paths(强连通分量)

题目链接:http://poj.org/problem?id=3177 题目大意是一个无向图给你n个点m条边,让你求出最少加多少条边 可以让任意两个点相通两条及以上的路线(每条路线点可以重复,但是每条路径上不能有重边),简单来说就是让你加最少的边使这个图变成一个双连通图. 首先用tarjan来缩点,可以得到一个新的无环图,要是只有一个强连通分量,那本身就是一个双连通图.要是多个强连通分量,那我们可以考虑缩点后度数为1的点(肯定是由这个点开始连新边最优),那我们假设数出度数为1的点的个数为cnt,

[2-SAT] poj 3678 Katu Puzzle

题目链接: http://poj.org/problem?id=3678 Katu Puzzle Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7888   Accepted: 2888 Description Katu Puzzle is presented as a directed graph G(V, E) with each edge e(a, b) labeled by a boolean operator 

poj 3678 Katu Puzzle(2-sat)

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

POJ 2186 Popular Cows 强连通分量模板

题意 强连通分量,找独立的块 强连通分量裸题 #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <iostream> using namespace std; const int maxn = 50005; int n, m; struct Edge { int v, next;