Wedding

Time Limit: 1000MS

 

Memory Limit: 65536K

Total Submissions: 12272

 

Accepted: 3751

 

Special Judge

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

​Waterloo Local Contest​​, 2007.9.29

 

题意:

n-1对夫妇去参加一对新人的婚礼。一个很长很长的桌子的两侧(面对面)。新郎新娘在桌子面对面座。夫妻必须分开做

同时,一些人之间有通奸关系(通奸不分性别,而且新郎新娘也可能通奸!!!!),新娘也不希望有通奸关系的人同时坐在她对面的一排。

问你可否满足新娘的要求,可以的话,输出一种方案
 

分析:

2-SAT的经典例题,这题不是很难。

饶齐大佬讲的很好

由于有n对夫妇(0号表示新婚夫妻).所以我们这里用0表示第0对的妻子,1表示第0对的丈夫. 2*i表示第i对的夫人,2*i+1表示第i对的丈夫.一共就有2*n个人了.

        然后对于每个人来说,把他分成两个节点,如果该人在做左边就mark[i*2],如果该人坐右边就mark[i*2+1].

        我令新娘直接坐左边即第0个人mark[0]=true,新郎直接坐右边即第1个人mark[1*2+1]=true.

        然后对于每对夫妻,因为他们不能在同一边,所以第i对夫妻中a= 2*i表示妻子,b=2*i+1表丈夫. 有这样的关系:

a在左边,那么b就在右边,a*2->b*2+1

a在右边,那么b就在左边,a*2+1->b*2

b在左边,那么a就在右边,b*2->a*2+1

b在右边,那么a就在左边,b*2+1->a*2

 然后对于每对有奸情的人a与b,因为它们不能同时在新娘对面(右边),所以:

a*2+1->b*2

b*2+1->a*2

        注意首先我们定了新娘(0号)在左边,新郎(第1号人)一定在右边,所以我们要先加上:

0*2+1->0*2  和 1*2->1*2+1 

这样就保证了新娘和新郎在固定的那边不动.

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<cmath>
using namespace std;
const int maxn=30000+10;
struct TwoSAT
{
int n;//原始图的节点数(未翻倍)
vector<int> G[maxn*2];//G[i]==j表示如果mark[i]=true,那么mark[j]也要=true
bool mark[maxn*2];//标记
int S[maxn*2],c;//S和c用来记录一次dfs遍历的所有节点编号

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

//加入(x,xval)或(y,yval)条件
//xval=0表示假,yval=1表示真
void add_clause(int x,int xval,int y,int yval)
{
x=x*2+xval;
y=y*2+yval;
G[x].push_back(y);
// G[y^1].push_back(x);
}

//从x执行dfs遍历,途径的所有点都标记
//如果不能标记,那么返回false
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;
}

//判断当前2-SAT问题是否有解
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;
}
}TS;
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
if(n==0&&m==0) break;
TS.init(n*2);
左边为0,右边为1
TS.add_clause(0,1,0,0);//新娘放左
TS.add_clause(1,0,1,1);//新郎放右
for(int i=1;i<n;i++)
{
int a=i*2; //妻子
int b=i*2+1;//丈夫,妻子和丈夫不能再同一边
TS.add_clause(a,0,b,1);
TS.add_clause(a,1,b,0);
TS.add_clause(b,0,a,1);
TS.add_clause(b,1,a,0);
}

for(int i=0;i<m;i++)
{
int a,b;
char s1[10],s2[10];
scanf("%d%s%d%s",&a,s1,&b,s2);
if(s1[0]=='w') a=a*2;
else a=a*2+1;
if(s2[0]=='w') b=b*2;
else b=b*2+1;
TS.add_clause(a,1,b,0);
TS.add_clause(b,1,a,0);
}
if(!TS.solve()) printf("bad luck\n");
else
{
for(int i=2;i<2*n;i+=2)
{
if(TS.mark[i*2])
printf("%dw ",i/2);
if(TS.mark[(i+1)*2])
printf("%dh ",i/2);
}
printf("\n");
}
}
return 0;
}