首页 > 代码库 > HDU 3062 Party(2-sat 模板题 tarjan )

HDU 3062 Party(2-sat 模板题 tarjan )

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3062


Problem Description
有n对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有1人可以列席。在2n 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的2个人是不会同时出现在聚会上的。有没有可能会有n 个人同时列席?
 
Input
n: 表示有n对夫妻被邀请 (n<= 1000)
m: 表示有m 对矛盾关系 ( m < (n - 1) * (n -1))

在接下来的m行中,每行会有4个数字,分别是 A1,A2,C1,C2
A1,A2分别表示是夫妻的编号
C1,C2 表示是妻子还是丈夫 ,0表示妻子 ,1是丈夫
夫妻编号从 0 到 n -1
 
Output
如果存在一种情况 则输出YES
否则输出 NO
 
Sample Input
2 1 0 1 1 1
 
Sample Output
YES
 
Source
2009 Multi-University Training Contest 16 - Host by NIT 


代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;
#define M 4000017
#define N 100017
//a<<1 和 (a<<1) + 1。a<<1表示妻子,(a<<1) + 1表示丈夫
//连接某边是为了推出矛盾。x->y表示选x则必须选y
//注意方向
struct node
{
    int s, t;
    int nxt;
} e[M];
int n, m;
int idx, ans, tp, cont;
int dfn[N],vis[N],low[N],head[N],st[N],belong[N];

void add(int s,int t)
{
    e[cont].s = s;
    e[cont].t = t;
    e[cont].nxt = head[s];
    head[s] = cont++;
}
void build_grap(int a, int b, int c, int d)//建图
{
    if(c==0 && d==0)//两个妻子
    {
        add(a<<1, (b<<1)+1);
        add(b<<1, (a<<1) + 1);
    }
    else if(c==0 && d==1)//妻子和丈夫
    {
        add((a<<1), (b<<1));
        add((b<<1)+1, (a<<1)+1);
    }
    else if(c==1 && d==0)//丈夫和妻子
    {
        add((a<<1) + 1, (b<<1) + 1);
        add(b<<1, a<<1);
    }
    else if(c==1 && d==1)//两个丈夫有矛盾
    {
        add((a<<1)+1, b<<1);
        add((b<<1)+1, a<<1);
    }
}
void tarjan(int u)
{
    dfn[u] = low[u] = ++idx;
    vis[u] = 1;
    st[++tp] = u;
    int v ;
    for(int i = head[u]; i != -1; i = e[i].nxt)
    {
        v = e[i].t ;
        if(!dfn[v])
        {
            tarjan(v) ;
            low[u] = min(low[u],low[v]);
        }
        else if(vis[v])
            low[u] = min(low[u],dfn[v]);
    }
    if(dfn[u] == low[u])
    {
        ans++;
        while(1)
        {
            v = st[tp--];
            vis[v] = 0;
            belong[v] = ans;
            if(v == u)
                break;
        }
    }
}
bool _2sat()
{
    memset(vis,0,sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    idx = tp = ans = 0;
    for(int i = 0; i < 2*n; i++)
        if(!dfn[i])
            tarjan(i) ;
    for(int i = 0; i < n; i++)
        if(belong[2*i]==belong[(2*i)^1])//矛盾
            return false ;
    return true;
}

int main()
{
    int a, b, c, d;
    while(~scanf("%d%d",&n,&m))
    {
        cont = 0;
        memset(head,-1,sizeof(head));
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            //int u, v;
            //u = a*2+c; v = b*2+d;
            //add(u, v^1); add(v, u^1);
            build_grap(a, b, c, d);
        }
        if(_2sat())
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0 ;
}


HDU 3062 Party(2-sat 模板题 tarjan )