http://poj.org/problem?id=3648

新娘和新郎   和其他夫妇 一共n对 每对夫妇不能做在同一侧  而且有奸情的人两个人(男女 男男 女女 出题人口味好重呀)不能同时坐在新娘的对面

2-SAT  

限制条件 n对夫妇一共2×n个人 0--n-1 是新娘  n--2×n-1是对应新郎  染色时 1代表和新娘同侧 -1代表不同侧

首先 新娘必须和新娘同侧2×n-->0 新郎必须和新娘对面n-->n+2×n  

其他夫妇必须异侧

有奸情的有一个在新娘对面 另一个一定和新娘同侧

代码及其注释:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#define LL long long

using namespace std;

const int N=150;
int head1[N],I1;
int head2[N],I2;
struct ss
{
    int j,next;
}side1[N*N],side2[N*N];
int low[N],dfn[N],f[N],deep;
bool in[N],visited[N];
int num[N],sele[N];
stack<int>st;
queue<int>qt;
vector<int>vt[N];
void build1(int x,int y)
{
    side1[I1].j=y;
    side1[I1].next=head1[x];
    head1[x]=I1++;
}
void build2(int x,int y)
{
    side2[I2].j=y;
    side2[I2].next=head2[x];
    head2[x]=I2++;
}
void Tarjan(int x)//将环缩点
{
    visited[x]=true;
    in[x]=true;
    st.push(x);
    low[x]=dfn[x]=deep++;
    for(int t=head1[x];t!=-1;t=side1[t].next)
    {
        int k=side1[t].j;
        if(visited[k]==false)
        {
            Tarjan(k);
            low[x]=min(low[x],low[k]);
        }else if(in[k]==true)
        {
            low[x]=min(low[x],dfn[k]);
        }
    }
    if(low[x]==dfn[x])
    {
        while(st.top()!=x)
        {
            int k=st.top();
            st.pop();
            in[k]=false;
            f[k]=x;
            vt[x].push_back(k);
        }
        int k=st.top();
        st.pop();
        in[k]=false;
        f[k]=x;
    }
}
void Fsearch(int x)//建立新图
{
    for(int t=head1[x];t!=-1;t=side1[t].next)
    {
        int k=side1[t].j;
        if(f[x]!=f[k])
        {
            build2(f[k],f[x]);
            ++num[f[x]];
        }
    }
}
void color(int x,int K)//染色 本环和相对的环 染不同色
{
    x=f[x];
    sele[x]=1;
    for(unsigned int i=0;i<vt[x].size();++i)
    {sele[vt[x][i]]=1;}
    x=(x<K)?x+K:x-K;
    x=f[x];
    sele[x]=-1;
    for(unsigned int i=0;i<vt[x].size();++i)
    {sele[vt[x][i]]=-1;}
}
void subnum(int x)//拓扑 减边
{
    for(int t=head2[x];t!=-1;t=side2[t].next)
    {
        int k=side2[t].j;
        --num[f[k]];
        if(num[f[k]]==0)
        qt.push(f[k]);
    }
}
int main()
{
    //freopen("data.txt","r",stdin);
    int n,m;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
        break;
        memset(head1,-1,sizeof(head1));
        I1=0;
        build1(0+2*n,0);//新娘和自己同侧
        build1(n,n+2*n);//新郎对面
        for(int i=1;i<n;++i)
        {
            build1(i,i+n+2*n);//其他夫妇 不能同侧
            build1(i+n,i+2*n);
            build1(i+2*n,i+n);
            build1(i+n+2*n,i);
        }
        for(int i=0;i<m;++i)
        {
            int k1,k2;
            char c1,c2;
            scanf("%d%c%d%c",&k1,&c1,&k2,&c2);
            if(c1=='h')
            k1+=n;
            if(c2=='h')
            k2+=n;
            build1(k1+2*n,k2);//有一个在新娘对面 另一个一定在新娘同侧
            build1(k2+2*n,k1);
        }
        while(!st.empty())
        st.pop();
        for(int i=0;i<4*n;++i)
        {vt[i].clear();f[i]=i;}
        memset(in,false,sizeof(in));
        memset(visited,false,sizeof(visited));
        deep=0;
        int l;
        for(l=0;l<4*n;++l)
        {
            if(visited[l]==false)
            Tarjan(l);
            if(l<2*n&&f[l]==f[l+2*n])
            break;
        }
        if(l<2*n)
        printf("bad luck\n");
        else
        {
            memset(head2,-1,sizeof(head2));
            memset(num,0,sizeof(num));
            I2=0;
            for(int i=0;i<4*n;++i)//将缩点 建新边
            Fsearch(i);
            for(int i=0;i<4*n;++i)
            if(f[i]==i&&num[i]==0)//拓扑中 为0的入队列
            qt.push(i);
            memset(sele,0,sizeof(sele));
            while(!qt.empty())
            {
                int k=qt.front();
                qt.pop();
                if(sele[k]==0)//染色
                color(k,2*n);
                subnum(k);
            }
            for(int i=1;i<n;++i)
            {
                if(sele[i]==1)
                printf("%dw",i);
                else
                printf("%dh",i);
                if(i<n-1)
                printf(" ");
                else
                printf("\n");
            }
        }
    }
    return 0;
}

  

posted on 2012-08-17 08:28  夜->  阅读(151)  评论(0编辑  收藏  举报