poj 3648 Wedding

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;

}

  

你可能感兴趣的:(poj)