码迷,mamicode.com
首页 > 编程语言 > 详细

POJ 3648 Wedding(2-SAT 拓扑排序输出任意一种解决方案)

时间:2015-08-17 19:30:44      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:2-sat   poj   

题目链接:http://poj.org/problem?id=3648


Description

Up to thirty couples will attend a wedding feast, at which they will be seated on either side of a long table. The bride and groom sit at one end, opposite each other, and the bride wears an elaborate headdress that keeps her from seeing people on the same side as her. It is considered bad luck to have a husband and wife seated on the same side of the table. Additionally, there are several pairs of people conducting adulterous relationships (both different-sex and same-sex relationships are possible), and it is bad luck for the bride to see both members of such a pair. Your job is to arrange people at the table so as to avoid any bad luck.

Input

The input consists of a number of test cases, followed by a line containing 0 0. Each test case gives n, the number of couples, followed by the number of adulterous pairs, followed by the pairs, in the form "4h 2w" (husband from couple 4, wife from couple 2), or "10w 4w", or "3h 1h". Couples are numbered from 0 to n - 1 with the bride and groom being 0w and 0h.

Output

For each case, output a single line containing a list of the people that should be seated on the same side as the bride. If there are several solutions, any one will do. If there is no solution, output a line containing "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

Source



题意:

有一对新人结婚,邀请了 n 对夫妇去参加婚礼。
有一张很长的桌子,每个人只能坐在桌子的两边,

还要满足下面的要求:

1.每对夫妇不能坐在同一侧 

2.n对夫妇之中可能有通奸关系(包括男男,男女,女女),有通
奸关系的不能同时坐在新娘的对面,可以分开坐,可以
同时坐在新娘这一侧。

如果存在一种可行的方案,输出与新娘同侧的人。
 

PS:


求解的时候去选择和新郎同一侧的人,输出的时候换一下就是新娘同一侧的人。
如果i和j有奸情,则增加一条i到j‘,j到i‘的边,
同时增加一条新娘到新郎的边,表示必须选新郎。
 
本题直接选新娘一边的容易错。因为新娘也可能有奸情,需要排除


代码如下:

/*
1.根据偷奸关系建图(1h和2h有偷奸关系,建边1h->2w    2h->1w)
2.求强连通分量
3.判断有无解(任一对夫妇不在同一强连通分量中,有解;否则无解)
4.缩点建图(建反向图)
5.拓扑排序
6.由底向上求解(由于上面建的是反向图,所以自顶(无入度)向下)
至此,选出来的是做新娘对面的,要求输出,坐在新娘一边的
*/
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
//2-SAT 强连通缩点
const int MAXN = 1010;
const int MAXM = 100010;
struct Edge
{
    int to;
    int next;
} edge[MAXM];
int head[MAXN],tot;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值1~scc
int Index,top;
int scc;
bool Instack[MAXN];
int num[MAXN];
void Tarjan(int u)//tarjan求强连通分量  
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if( !DFN[v] )
        {
            Tarjan(v);
            if(Low[u] > Low[v])Low[u] = Low[v];
        }
        else if(Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if(Low[u] == DFN[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc]++;
        }
        while(v != u);
    }
}

//判断是否有解
bool solvable(int n)//n是总个数,需要选择一半
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    memset(num,0,sizeof(num));
    Index = scc = top = 0;
    for(int i = 0; i < n; i++)
        if(!DFN[i])
            Tarjan(i);
    for(int i = 0; i < n; i += 2)
    {
        if(Belong[i] == Belong[i^1])
            return false;
    }
    return true;
}

//拓扑排序求任意一组解部分
queue<int>q1,q2;
vector<vector<int> > dag;//缩点后的逆向DAG图
char color[MAXN];//染色,为'R'是选择的
int indeg[MAXN];//入度
int cf[MAXN];
void topsort(int n)
{
    dag.assign(scc+1,vector<int>());
    memset(indeg,0,sizeof(indeg));
    memset(color,0,sizeof(color));
    for(int u = 0; u < n; u++)//构建反向缩点图
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(Belong[u] != Belong[v])
            {
                dag[Belong[v]].push_back(Belong[u]);
                indeg[Belong[u]]++;
            }
        }
    for(int i = 0; i < n; i += 2)
    {
        cf[Belong[i]] = Belong[i^1];
        cf[Belong[i^1]] = Belong[i];
    }
    while(!q1.empty())q1.pop();
    while(!q2.empty())q2.pop();
    for(int i = 1; i <= scc; i++)
        if(indeg[i] == 0)
            q1.push(i);
    while(!q1.empty())
    {
        int u = q1.front();
        q1.pop();
        if(color[u] == 0)
        {
            color[u] = 'R';
            color[cf[u]] = 'B';
        }
        int sz = dag[u].size();
        for(int i = 0; i < sz; i++)
        {
            indeg[dag[u][i]]--;
            if(indeg[dag[u][i]] == 0)
                q1.push(dag[u][i]);
        }
    }
}
int change(char s[])
{
    int ret = 0;
    int i = 0;
    while(s[i]>='0' && s[i]<='9')
    {
        ret *= 10;
        ret += s[i]-'0';
        i++;
    }
    if(s[i] == 'w') //女
        return 2*ret;
    else            //男
        return 2*ret+1;
}
int main()
{
    int n, m;
    char s1[17], s2[17];
    while(~scanf("%d%d",&n,&m))
    {
        if(n == 0 && m == 0)
            break;
        init();
        while(m--)
        {
            scanf("%s%s",s1,s2);
            int u = change(s1);
            int v = change(s2);
            addedge(u^1,v);//注意方向,模拟一下
            addedge(v^1,u);
        }
        addedge(1,0);
        if(solvable(2*n))//判断是否有解
        {
            topsort(2*n);
            for(int i = 1; i < n; i++)
            {
                //注意这一定是判断color[Belong[
                if(color[Belong[2*i]] == 'R')
                    printf("%dw",i);
                else
                    printf("%dh",i);
                if(i < n-1)
                    printf(" ");
                else
                    printf("\n");
            }
        }
        else
            printf("bad luck\n");
    }
    return 0;
}




版权声明:本文为博主原创文章,未经博主允许不得转载。

POJ 3648 Wedding(2-SAT 拓扑排序输出任意一种解决方案)

标签:2-sat   poj   

原文地址:http://blog.csdn.net/u012860063/article/details/47729755

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!