题意:
有一对新人结婚,邀请n对夫妇去参加婚礼
有一张很长的桌子,人只能坐在桌子的两边,还要满足下面的要求:
- 每对夫妇不能坐在同一侧
- n对夫妇之中可能有通奸关系,有通奸关系的不能同时坐在新娘的对面,可以分开坐,可以同时坐在新娘这一侧
- 新郎新娘不能坐在同一侧
如果存在一种可行的方案,输出与新娘同侧的人
分析:
题目描述真的是。。。
我们构造一个图,选出要坐在新娘对面的人
设夫妇为
(h1,w1),(h2,w2)
(
h
1
,
w
1
)
,
(
h
2
,
w
2
)
如果
h1,h2
h
1
,
h
2
存在矛盾:
h1−>w2,h2−>w1
h
1
−
>
w
2
,
h
2
−
>
w
1
如果
h1,w2
h
1
,
w
2
存在矛盾:
h1−>h2,w2−>w1
h
1
−
>
h
2
,
w
2
−
>
w
1
如果
w1,h2
w
1
,
h
2
存在矛盾:
w1−>w2,h2−>h1
w
1
−
>
w
2
,
h
2
−
>
h
1
如果
w1,w2
w
1
,
w
2
存在矛盾:
w1−>h2,w2−>h1
w
1
−
>
h
2
,
w
2
−
>
h
1
同时添加一条边,连接新娘到新郎,表示必须选新郎坐在新娘对面
对图染色,输出与新娘颜色相同的人
还是要注意编号从0开始
tip
0是新娘,1是新郎
偶数妻子,奇数丈夫
不要忘了初始化
代码是最小解
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=20010;
int n,m,st[N<<1],tot=0,top,s[N<<1];
struct node{
int y,nxt;
};
node way[N<<2];
bool col[N<<1];
void add(int u,int w) {
tot++;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;
}
int fan(int x) {
if (x&1) return x-1;
else return x+1;
}
bool paint(int x) {
if (col[x]) return 1;
if (col[fan(x)]) return 0;
col[x]=1;
s[++top]=x;
for (int i=st[x];i;i=way[i].nxt)
if (!paint(way[i].y)) return 0;
return 1;
}
bool solve() {
memset(col,0,sizeof(col));
for (int i=0;i<2*n;i+=2)
if (!col[i]&&!col[i+1]) {
top=0;
if (!paint(i)) {
while (top) col[s[top--]]=0;
if (!paint(i+1)) return 0;
}
}
return 1;
}
int main()
{
int a,b;
char s1[2],s2[2];
while (scanf("%d%d",&n,&m)!=EOF&&n+m) { //h 2*n+1 w 2*n
memset(st,0,sizeof(st)); tot=0;
for (int i=1;i<=m;i++) {
scanf("%d%s %d%s",&a,s1,&b,s2);
if (s1[0]=='h'&&s2[0]=='h') {
add(a*2+1,b*2); add(b*2+1,a*2);
}
else if (s1[0]=='h'&&s2[0]=='w') {
add(a*2+1,b*2+1); add(b*2,a*2);
}
else if (s1[0]=='w'&&s2[0]=='h') {
add(a*2,b*2); add(b*2+1,a*2+1);
}
else {
add(a*2,b*2+1); add(b*2,a*2+1);
}
}
add(0,1);
if (solve()) {
bool f=col[0]; //与新娘同侧
for (int i=2;i<n*2;i+=2)
if (col[i]==f) printf("%dw ",i/2);
else printf("%dh ",i/2);
printf("\n");
}
else printf("bad luck\n");
}
return 0;
}