POJ 3648 Wedding

2-SAT,直接选择新娘一侧的比较难做,所以处理的时候选择新郎一侧的,最后反着输出就可以。

A和B通奸的话,就建边 A->B'以及B->A’,表示 A在新郎一侧的话,B一定不在;B在新郎一侧的话,A一定不在。

然后再把新郎的mark标记为1,表示新郎一定选择。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn=8000+5;
int N,m;
char s1[10],s2[10];

struct TwoSAT
{
    int n;
    vector<int> G[maxn*2];
    bool mark[maxn*2];
    int S[maxn*2],c;

    bool dfs(int x)
    {
        if(mark[x^1]) return false;
        if(mark[x]) return true;
        mark[x]=true;
        S[c++]=x;
        for(int i=0;i<G[x].size();i++)
            if(!dfs(G[x][i])) return false;
        return true;
    }

    void init(int n)
    {
        this->n=n;
        for(int i=0;i<n*2;i++) G[i].clear();
        memset(mark,0,sizeof mark);
    }

    void add_clause(int x,int y)
    {
        G[x].push_back(y^1);
        G[y].push_back(x^1);
    }

    bool solve()
    {
        for(int i=0;i<2*n;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;
    }

    //输出字典序最小的解
    void Printf()
    {
        for(int i=1;i<n;i++)
        {

            if(mark[2*i]) printf("%dw",i);
            else printf("%dh",i);

            if(i<n-1) printf(" ");
            else printf("
");
        }
    }
};

int main()
{
    TwoSAT T;
    while(~scanf("%d%d",&N,&m))
    {
        if(N==0&&m==0) break;
        T.n=N; T.init(T.n);
        for(int i=0;i<m;i++)
        {
            int a=0,b=0;
            scanf("%s%s",s1,s2);

            for(int j=0;j<strlen(s1)-1;j++)
                a=a*10+s1[j]-'0';
            for(int j=0;j<strlen(s2)-1;j++)
                b=b*10+s2[j]-'0';

            if(s1[strlen(s1)-1]=='h') a=a*2;
            else a=a*2+1;

            if(s2[strlen(s2)-1]=='h') b=b*2;
            else b=b*2+1;

            T.add_clause(a,b);
        }
        T.mark[0]=1;
        if(T.solve()) T.Printf();
        else printf("bad luck
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/4906249.html