HDU 4115 2-SAT

【题目链接】

http://acm.hdu.edu.cn/showproblem.php?pid=4115

【题目大意】

Bob和Alice玩剪刀石头布,一个玩n轮,Alice已经知道了Bob每次要出什么,

1代表剪刀,2代表石头,3代表布,然后Bob对Alice作出了一些限制:

给m行,每行是a b k,如果k是0,表示Alice第a次和b次出的拳必须相同,

如果k是1,表示Alice第a次和b次出的拳必须不相同。

一但Alice破坏了这个限制规则,或者输了一局,那么Alice就彻底输了。问Alice可不可能赢?

【分析】

        因为Alice一次都不能输,所以根据Bob出的拳,Alice只可以赢或者平局,即每次有两种选择,是2-SAT模型

        然后会有一些矛盾对,假设第a次可以出a1,a2, 第b次可以出b1和b2

        如果第a次和b次要求相同, 但是a1和b1不同,说明这个矛盾,建立连接 a1—>b2, b1—>a2.

        (a1与b1不同时最多有4种可能的情况需要考虑)

        同理,第a次和b次要求不相同,但是a1和b2相同,说明这个矛盾,建立链接a1—>b1,  b2—>a2

       所以一共有八种情况需要考虑

【代码】

#include<iostream>
#include<cstring>
#include<stack>
#include<iomanip>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stdio.h>
using namespace std;
# define ll long long
#define eps 1e-5
const int maxn=20010;
int a[maxn],b[maxn],c[maxn];
int op[maxn],vis[maxn],low[maxn],dfn[maxn];
int pt[maxn],stk[maxn],color[maxn],pos[maxn],deg[maxn];
vector<int>vc[100100],vc2[100100];
int n,m,sig,cnt,tot,cont;
void add(int x,int y){
    vc[x].push_back(y);
}
void top(){
    memset(pt,0,sizeof(pt));
    queue<int>s;
    for(int i=1;i<=sig;i++){
        if(deg[i]==0) s.push(i);
    }
    while(!s.empty()){
        int u=s.front();
        if(pt[u]==0){
            pt[u]=1;
            pt[pos[u]]=2;
        }
        s.pop();
        for(int i=0;i<vc2[u].size();i++){
            int v=vc2[u][i];
            deg[v]--;
            if(deg[v]==0) s.push(v);
        }
    }
    cont=0;
    for(int i=1;i<=n;i++) {
        if(pt[color[i]]==1) op[cont++]=i;
    }
}
void tarjan(int u){
    vis[u]=1;
    dfn[u]=low[u]=cnt++;
    stk[++tot]=u;
    for(int i=0;i<vc[u].size();i++){
        int v=vc[u][i];
        if(vis[v]==0) tarjan(v);
        if(vis[v]==1) low[u]=min(low[u],low[v]);
    }
    if(low[u]==dfn[u]) {
        sig++;
        do{
            vis[stk[tot]]=-1;
            color[stk[tot]]=sig;
        }while(stk[tot--]!=u);
    }
}
void init(){
    sig=0;cnt=1;tot=-1;
    memset(deg,0,sizeof(deg));
    memset(stk,0,sizeof(stk));
    memset(dfn,0,sizeof(dfn));
    memset(vis,0,sizeof(vis));
    memset(color,0,sizeof(color));
    for(int i=0;i<maxn;i++) {
        vc[i].clear();
        vc2[i].clear();
    }
}
int solve(){
    for(int i=1;i<=n*2;i++) {
        if(vis[i]==0) tarjan(i);
    }
    for(int i=1;i<=n;i++) {
        if(color[i]==color[i+n]) return 0;
        pos[color[i]]=color[i+n];
        pos[color[i+n]]=color[i];
    }
    for(int i=1;i<=n*2;i++){
        for(int j=0;j<vc[i].size();j++){
            int v=vc[i][j];
            if(color[i]!=color[v]){
                deg[color[i]]++;
                vc2[color[v]].push_back(color[i]);
            }
        }
    }
    top();
    return 1;
}
int bob[maxn],bt[4]={0,2,3,1};
int main()
{
     int cas;
     scanf("%d",&cas);
     int kc;
     for(kc=1;kc<=cas;kc++)
     {
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
          int x;
          scanf("%d",&x);
          bob[i]=x;
          bob[i+n]=bt[x];
        }
        
        for(int i=1;i<=m;i++)
        {
          int a,b,k;
          scanf("%d%d%d",&a,&b,&k);
          if(k==0)
          {
                if(bob[a]!=bob[b])
                {
                   add(a,b+n);
                   add(b,a+n);
                }
                if(bob[a]!=bob[b+n])
                {
                  add(a,b);
                  add(b+n,a+n);
                }
                if(bob[a+n]!=bob[b])
                {
                  add(a+n,b+n);
                  add(b,a);
                }
                if(bob[a+n]!=bob[b+n])
                {
                  add(a+n,b);
                  add(b+n,a);
                }
          }
          else
          {
                if(bob[a]==bob[b])
                {
                  add(a,b+n);
                  add(b,a+n);
                }
                if(bob[a]==bob[b+n])
                {
                  add(a,b);
                  add(b+n,a+n);
                }
                if(bob[a+n]==bob[b])
                {
                  add(a+n,b+n);
                  add(b,a);
                }
                if(bob[a+n]==bob[b+n])
                {
                  add(a+n,b);
                  add(b+n,a);
                }
          }
        }
        printf("Case #%d: ",kc);
        if(solve())
        printf("yes\n");
        else
        printf("no\n");
     }
     return 0;
}

 

上一篇:C - Wandering Robot(ZOJ 4115)


下一篇:Zipper OpenJ_Bailian - 2192 (DP最长公共子串)