首页 > 代码库 > HDU 4115 Eliminate the Conflict【2-sat】

HDU 4115 Eliminate the Conflict【2-sat】

转载请注明出处:http://blog.csdn.net/u013912596

题目大意:

Alice和Bob玩若干轮石头剪刀布的游戏,Alice已经知道了Bob在每一轮会出什么,但是Bob会给出一些Alice的限制条件,问Alice在不打破这些限制的情况下,有没有可能赢。

 限制格式为(i,j,w),i,j代表第几轮,w=1的话,要求Alice在第i轮和第j轮的策略不能相同,w=0的话,要求Alice在第i轮和第j轮的策略必须相同。

思路:

     刚开始以为这个题是个DP,按照这个想了一下,发现要求相同的话倒是好说,但是要求不同的时候解不出来,于是果断换思路。

后来画了几张图,怎么看都像是图论。。突然想到了2-sat!立马感觉就是2-sat了!感觉简直对的不行!于是T神赶紧把2-sat的板子敲上去,我思考怎么建图。
思路如下:
                我们将Bob的出手顺序存到a[]数组中,按题目所说,1代表石头,2代表布,3代表剪刀。由于Alice不能输,那么知道Bob的出手状况之后,在不考虑限制条件的情况下,Alice想要不输每一轮只能选择赢或者平局,这就保证了每一轮只可能存在两种情况。首先规定如下规则:
                        a[i]=1时,Alice只能选择1,2,令此时的1为true,2为false。

a[i]=2时,Alice只能选择2,3,令此时的2为true,3为false。

a[i]=3时,Alice只能选择3,1,令此时的1为true,3为false。

可能有的同学会说,这不是有的矛盾了吗。。。(博主是蒟蒻。。当时也在纠结这个问题。。),后来发现其实没有影响,只是表示这两种状态而已,只要一开始定好规则,按照这个规则建边就好了。

好!下面开始认真的建边了!

对每条限制条件进行处理(Ai,Aj表示Alice在该轮的状态,true or false):

1.当a[i]==a[j],(1).w==1(不同):Ai xor Aj =1

   (2).w==0(相同):Ai xor Aj =0

2.当a[i]==1&&a[j]==2时,(1).w==1(不同):Ai or ~Aj =1

   (2).w==0(相同):~Ai and Aj =1(这个地方做得时候和上一条建边高反了T.T,结果调了一天。。。泪面。。)

3.当a[i]==2&&a[j]==3时,(1).w==1(不同):~Ai or ~Aj =1

   (2).w==0(相同):Ai and Aj =1

4.当a[i]==1&&a[j]==3时,(1).w==1(不同):Ai or Aj =1

   (2).w==0(相同):~Ai and ~Aj =1

好!有上述条件之后,我们就可以开始建边啦~(如果a[i]==2,a[j]==1什么的,交换一下 i , j 就好啦)下面是各个公式对应的建边方式:

把每个值是1(a)和0(~a)为两种状态,分清楚各种操作的本质就很简单了

AND 结果为1:建边 ~x->x,~y->y (两个数必须全为1)

AND 结果为0:建边 y->~x,x->~y (两个数至少有一个为0)

OR 结果为1:建边 ~x->y,~y->x (两个数至少有一个为1)

OR 结果为0:建边 x->~x,y->~y (两个数必须全为0)

XOR 结果为1:建边 x->~y,y->~x,~y->x,~x->y (两个数必须不同)

XOR 结果为0:建边 x->y,y->x,~x->~y,~y->~x (两个数必须相同)

好吧。。这道题建完边,用模板跑一边,结果就出来了,挺简单的。

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
int V;//mind assign
const int MAX_V=22222;
vector<int> G[MAX_V];
vector<int> rG[MAX_V];
vector<int> vs;
bool used[MAX_V];
int cmp[MAX_V];
int a[MAX_V];
void add_edge(int from,int to){
    G[from].push_back(to);
    rG[to].push_back(from);
}
void dfs(int v){
    used[v]=true;
    for(int i=0;i<G[v].size();i++){
        if(!used[G[v][i]]) dfs(G[v][i]);
    }
    vs.push_back(v);
}
void rdfs(int v,int k){
    used[v]=true;
    cmp[v]=k;
    for(int i=0;i<rG[v].size();i++)
        if(!used[rG[v][i]]) rdfs(rG[v][i],k);
}
int scc(){
    memset(used,0,sizeof(used));
    vs.clear();
    for(int v=0;v<V;v++){
        if(!used[v]) dfs(v);
    }
    memset(used,0,sizeof(used));
    int k=0;
    for(int i=vs.size()-1;i>=0;i--){
        if(!used[vs[i]]) rdfs(vs[i],k++);
    }
    return k;
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("D:/in.txt","r",stdin);
        //freopen("D:/out.txt","w",stdout);
    #endif // ONLINE_JUDGE
    int T;scanf("%d",&T);
    int cas=1;
    while(T--){
        for(int i=0;i<MAX_V;i++) G[i].clear();
        for(int i=0;i<MAX_V;i++) rG[i].clear();
        memset(cmp,0,sizeof(cmp));
        int n,m;
        printf("Case #%d: ",cas++);
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++){
            scanf("%d",a+i);
        }
        V=2*n;
        for(int k=1;k<=m;k++){
            int i,j,w;
            scanf("%d%d%d",&i,&j,&w);
            i--;j--;

            if(a[i]==a[j]){
                if(w==1){
                    add_edge(i,j+n);
                    add_edge(j,i+n);
                    add_edge(i+n,j);
                    add_edge(j+n,i);
                }else{
                    add_edge(i,j);
                    add_edge(j,i);
                    add_edge(i+n,j+n);
                    add_edge(j+n,i+n);
                }
            }else{
                if(a[i]+a[j]==3){
                    if(a[i]!=1) swap(i,j);//这里必须要交换保证顺序正确
                    if(w==1){
                        add_edge(i+n,j+n);
                        add_edge(j,i);
                    }else{
                        add_edge(i,i+n);
                        add_edge(j+n,j);
                    }
                }else if(a[i]+a[j]==4){
                    //if(a[i]!=1) swap(i,j);//这里可以不用交换,因为操作一样
                    if(w==1){
                        add_edge(i,j+n);
                        add_edge(j,i+n);
                    }else{
                        add_edge(i+n,i);
                        add_edge(j+n,j);
                    }
                }else{
                    //if(a[i]!=2) swap(i,j);//同上
                    if(w==1){
                        add_edge(i+n,j);
                        add_edge(j+n,i);
                    }else{
                        add_edge(i,i+n);
                        add_edge(j,j+n);
                    }
                }
            }
        }
        //after build edges
        scc();

        bool isCon=false;
        for(int i=0;i<n;i++){
            if(cmp[i]==cmp[n+i]){
                printf("no\n");
                isCon=true;
                break;
            }
        }
        if(isCon) continue;
        printf("yes\n");
    }
    return 0;
}

HDU 4115 Eliminate the Conflict【2-sat】