HDU 4115 2-sat 石头剪刀布 拆点+约束

题意:

2个人玩石头剪刀布

A和B

n轮 m个约束条件(对A的约束)

下面n个数字表示B的出发 (1为石头 2为布 3为剪刀)

下面m行表示约束条件

u v papa 

papa = 1 表示 u v轮 A必须出一样 =0 表示u v轮必须出不一样

 

问A能否全胜

 

把一轮拆成: 出0 2 4的方法和 不出 1 3 5的方法

 

#include<stdio.h>  
#include<string.h>   
#include<iostream>   
#include<algorithm>   
#include<math.h>   
  
#define ll int   
using namespace std;  
  
inline ll Max(ll a,ll b){return a>b?a:b;}  
inline ll Min(ll a,ll b){return a<b?a:b;}  
  
  
#define N 10010*12   
#define M 10010*50   
  
struct Edge{  
    int to, nex;  
}edge[M];  
  
int head[N], edgenum;  
void addedge(int u, int v){  
    Edge E = {v, head[u]};  
    edge[edgenum] = E;  
    head[u] = edgenum ++;  
}  
  
bool mark[N];  
int Stack[N], top;  
void init(){  
    memset(head, -1, sizeof(head)); edgenum = 0;  
    memset(mark, 0, sizeof(mark));  
}  
  
bool dfs(int x){  
    if(mark[x^1])return false;//一定是拆点的点先判断   
    if(mark[x])return true;  
  
    mark[x] = true;  
    Stack[top++] = x;  
  
    for(int i = head[x]; i != -1; i = edge[i].nex)  
        if(!dfs(edge[i].to)) return false;  
  
    return true;  
}  
  
bool solve(int n){  
    for(int i = 0; i < n; i+=2)  
        if(!mark[i] && !mark[i^1])  
        {  
            top = 0;  
            if(!dfs(i))//dfs(i) 假设i成立    
            {//当i不成立时,把所有因i成立的点都取消标记   
                while( top ) mark[ Stack[--top] ] = false;  
                if(!dfs(i^1))  
                    return false;//若i的对立面也不成立则i点无解   
            }  
        }  
        return true;  
}  
  
  
int main(){  
    int n, i, j, k, m, t, Cas = 1; scanf("%d",&t);  
    while(t--){  
        scanf("%d %d",&n,&m);  
        init();  
  
        for(i = 0; i < n; i++)  
        {  
            addedge(6*i, 6*i+3);      
            addedge(6*i, 6*i+5);  
            addedge(6*i+2, 6*i+1);  
            addedge(6*i+2, 6*i+5);  
            addedge(6*i+4, 6*i+1);  
            addedge(6*i+4, 6*i+3);  
  
            int hehe;  
            scanf("%d",&hehe);  
  
            if(hehe == 1)  
            {  
                addedge(6*i+3, 6*i+0);  //不出布一定出石头   
                addedge(6*i+1, 6*i+2);//不出石头一定出布   
            }  
            if(hehe == 2)  
            {  
                addedge(6*i+3, 6*i+4);  
                addedge(6*i+5, 6*i+2);  
            }  
            if(hehe == 3)  
            {  
                addedge(6*i+5, 6*i+0);   
                addedge(6*i+1, 6*i+4);  
            }  
        }  
  
        while(m--)  
        {  
            int u, v, papa;  
            scanf("%d %d %d",&u,&v,&papa); u--, v--;  
            if(papa == 0)  
            {  
                addedge(6*u+0, 6*v+0);  
                addedge(6*u+4, 6*v+4);  
                addedge(6*u+2, 6*v+2);  
                addedge(6*v+0, 6*u+0);  
                addedge(6*v+4, 6*u+4);  
                addedge(6*v+2, 6*u+2);  
            }  
            else  
            {  
                addedge(6*u+0, 6*v+1);  
                addedge(6*u+2, 6*v+3);  
                addedge(6*u+4, 6*v+5);  
  
                addedge(6*v+0, 6*u+1);  
                addedge(6*v+2, 6*u+3);  
                addedge(6*v+4, 6*u+5);  
            }  
        }  
        if(solve(n*12))  
            printf("Case #%d: yes\n",Cas++);  
        else  
            printf("Case #%d: no\n",Cas++);  
    }  
    return 0;  
}  
/* 
2 
0 4 
4 0 
3 
0 1 24 
1 0 86 
24 86 0 
HDU 4115 必过 
*/  


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值