POJ 3648 Wedding(2-SAT)

Description
有一对新人结婚,邀请n对夫妇去参加婚礼。有一张很长的桌子,人只能坐在桌子的两边,还要满足下面的要求:
1.每对夫妇不能坐在同一侧
2.n对夫妇之中可能有通奸关系(包括男男,男女,女女),有通奸关系的不能同时坐在新娘的对面,可以分开坐,可以同时坐在新娘这一侧。
如果存在一种可行的方案,输出与新娘同侧的人
Input
多组用例,每组用例第一行两个整数n和m表示n对夫妇以及m组通奸关系,之后m行每行一组通奸关系t1c1 t2c2,其中c1==’h’表示t1是丈夫,c1==’w’表示t1是妻子(结婚的一对新人看做第一组夫妇),以0 0结束输入
Output
对于每组用例,如果存在一组可行方案则输出与新娘同侧的人,如果不存在则输出bad luck
Sample Input
10 6
3h 7h
5w 3w
7h 6w
8w 3w
7h 3w
2w 5h
0 0
Sample Output
1h 2h 3w 4h 5h 6h 7h 8h 9h
Solution
2-SAT判断可行性,因为新郎必须坐在新娘对面,所以对新郎要特判,与新郎有奸情的人一定要坐在新娘一侧,构图时就构造一个~t->t即可,与新娘有奸情的人做哪一侧都行,对于其他人,如果t1与t2有奸情,则构造~t1->t2和~t2->t1,接下来只需用tarjan算法求强联通分量并判断是否有使得布尔公式值为真的一组布尔变量赋值即可,注意,因为要输出可行方案,所以要记录可行方案
Code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
#define maxn 66
vector<int>g[maxn];  
stack<int>st;  
int n,m,scc,index;  
int low[maxn],dfn[maxn],instack[maxn],fa[maxn];  
int ans[maxn];//记录可行方案 
void init()//初始化 
{  
    scc=index=0;  
    while(!st.empty())st.pop();  
    for(int i=0;i<maxn;i++)g[i].clear();  
    memset(dfn,0,sizeof(dfn));  
    memset(instack,0,sizeof(instack));  
    memset(low,0,sizeof(low));
    memset(ans,0,sizeof(ans));
}  
void tarjan(int u)//求强联通分量 
{  
    dfn[u]=low[u]=++index;  
    instack[u]=1;  
    st.push(u);  
    int v,size=g[u].size();  
    for(int i=0;i<size;i++)  
    {  
        v=g[u][i];  
        if(!dfn[v]) 
        {  
            tarjan(v);  
            low[u]=min(low[u],low[v]);  
        }  
        else if(instack[v]) 
            low[u]=min(low[u],dfn[v]);  
    }  
    if(dfn[u]==low[u])  
    {  
        scc++;  
        do  
        {  
            v=st.top();  
            st.pop();  
            fa[v]=scc;  
            instack[v]=0;  
        }while(v!=u);  
    }  
}  
bool check()
{
    for(int i=0;i<2*n;i++)//求强联通分量 
        if(!dfn[i])
            tarjan(i);
    for(int i=0;i<2*n;i+=2)
    {
        if(fa[i]==fa[i+1])//矛盾 
            return false;
        if(fa[i]<fa[i+1])//该对夫妇的妻子需要坐在新娘一侧 
            ans[i/2]=i;
        else//该对夫妇的丈夫需要坐在新娘一侧 
            ans[i/2]=i+1;
    }
    return true;
}
int main()
{
    while(scanf("%d%d",&n,&m),n||m)
    {
        int t1,t2;
        char c1,c2;
        init();
        for(int i=0;i<m;i++)
        {
            scanf("%d%c%d%c",&t1,&c1,&t2,&c2);
            //奇数项存丈夫,偶数项存妻子 
            if(c1=='h') t1=2*t1+1;
            else t1=2*t1;
            if(c2=='h') t2=2*t2+1;
            else t2=2*t2;
            if(t1==1)//t2与新郎有奸情,其必须坐在新娘一侧 
                g[t2^1].push_back(t2);
            else if(t2==1)//t1与新郎有奸情,其必须坐在新娘一侧 
                g[t1^1].push_back(t1);
            else if(t1==0||t2==0)////考虑新娘的奸情 
            {;}
            else//考虑其他人的奸情 
            {
                g[t2^1].push_back(t1);
                g[t1^1].push_back(t2);
            }
        }
        if(check())//存在可行方案 
        {
            int i;
            for(i=1;i<n-1;i++)
            {
                if(ans[i]==i*2) printf("%dw ",i);
                else printf("%dh ",i);
            }
            if(ans[i]==i*2) printf("%dw\n",i);
            else printf("%dh\n",i);
        }
        else//不存在可行方案 
            printf("bad luck\n");
    }
    return 0;
}

你可能感兴趣的:(POJ 3648 Wedding(2-SAT))