hdu 4115 Eliminate the Conflict

题意:两个人玩石头剪刀布,其中一个人知道另一个人会出什么,因此这个人给另一个人提出了一些限制:A、B、K,如果K==0,表示第A局和第B局这两局这个人出的东西必须一样,K==1,表示不一样。给出第一个人会出什么,求第二个人能否保持不败。

思路:用2-SAT可以很好地解决这个问题,这个题要把每一局拆成6的点:出石头,不出石头,出布,不出布,出剪刀,不出剪刀。另外还要满足每一局不能出两样。对于每个限制,如果K==0,则要满足:如果出A局出布(剪刀or石头),B局必须出布(剪刀or石头)……,如果K==1,则要满足第A局和第B局不能出一样的。最后对于每一局,必须出可以平或者赢的拳,最后跑个2-SAT模板就行了~

 

代码:

 

#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=10000+10;
int w[maxn];
struct TwoSAT
{
    int n;
    vector<int>G[maxn*6];
    bool mark[maxn*6];
    int S[maxn*6],c;
    bool dfs(int u)
    {
        if(mark[u^1]) return false;
        if(mark[u]) return true;
        mark[u]=true;
        S[c++]=u;
        for(int i=0;i<G[u].size();++i)
        {
            if(!dfs(G[u][i])) return false;
        }
        return true;
    }
    void Init(int n)
    {
        this->n=n;
        memset(mark,0,sizeof(mark));
        for(int i=0;i<n*2;++i)
          G[i].clear();
    }
    void add_clause(int x,int xval,int y,int yval)
    {
        x=x*2+xval;
        y=y*2+yval;
        G[x^1].push_back(y);
        G[y^1].push_back(x);
    }
    bool solve()
    {
        for(int i=0;i<n*2;i+=2)
        {
            if(!mark[i]&&!mark[i+1])
            {
                c=0;
                if(!dfs(i))
                {
                    while(c>0) mark[S[--c]]=false;
                    if(!dfs(i+1)) return false;
                }
            }
        }
        return true;
    }
}solver;
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t,n,m,tcase=0;
    scanf("%d",&t);
    while(t--)
    {
        tcase++;
        scanf("%d%d",&n,&m);
        solver.Init(n*3);
        for(int i=0;i<n;++i)
          scanf("%d",&w[i]);
        for(int i=0;i<n;i++)
        {
            solver.add_clause(i*3,0,i*3+1,0);
            solver.add_clause(i*3+1,0,i*3+2,0);
            solver.add_clause(i*3+2,0,i*3,0);
        }
        int a,b,k;
        for(int i=0;i<m;++i)
        {
            scanf("%d%d%d",&a,&b,&k);
            a--;b--;
            if(k==0)
            {

                a*=3;b*=3;
                solver.add_clause(a,0,b,1);
                solver.add_clause(a,1,b,0);
                solver.add_clause(a+1,0,b+1,1);
                solver.add_clause(a+1,1,b+1,0);
                solver.add_clause(a+2,0,b+2,1);
                solver.add_clause(a+2,1,b+2,0);
            }
            else
            {
                a*=3;b*=3;
                solver.add_clause(a,0,b,0);
                //solver.add_clause(a,1,b,1);
                solver.add_clause(a+1,0,b+1,0);
                //solver.add_clause(a+1,1,b+1,1);
                solver.add_clause(a+2,0,b+2,0);
                //solver.add_clause(a+2,1,b+2,1);
            }
        }
        for(int i=0;i<n;++i)
        {
            a=i*3;
            if(w[i]==1)
            {
                solver.add_clause(a,1,a+1,1);
                //solver.mark[(a+2)*2]=true;
            }
            else if(w[i]==2)
            {
                solver.add_clause(a+1,1,a+2,1);
                //solver.mark[a*2]=true;
            }
            else
            {
                solver.add_clause(a+2,1,a,1);
                //solver.mark[(a+1)*2]=true;
            }
        }
        printf("Case #%d: ",tcase);
        if(solver.solve())
          puts("yes");
        else puts("no");
    }
    return 0;
}


 

你可能感兴趣的:(图论,2-sat)