您的位置:首页 > 其它

POJ 3648 Wedding[2-SAT]

2012-08-04 23:56 239 查看
题意: 有一对 新人举办婚礼,邀请了n-1对夫妇,有一张很长的桌子,要求左右的夫妇都分别坐在桌子的两侧,且知道了 m 对 人有关系,要求新娘对面不能出现有关系的两个人。

分析: 在 有关系的人之间连边,在所有夫妇之间连边,用奇数表示男的,偶数表示女的,用2-sat方法染色,最后输出不在新娘一边的人。

#include<stdio.h>
#include<string.h>
#define op(x) ((x)=='h'?1:0)
#define clr(x)memset(x,0,sizeof(x))
#define min(a,b)(a)<(b)?(a):(b)
#define maxn 3005
struct node
{
int to,next;
}e[1000000];
int tot;
int head[maxn];
void add(int s,int u)
{
e[tot].to=u;
e[tot].next=head[s];
head[s]=tot++;
}
int n,m,ti,top,sn;
int dfn[maxn],low[maxn];
int ins[maxn],sta[maxn];
int vis[maxn],col[maxn];
void tar(int u)
{
dfn[u]=low[u]=++ti;
sta[++top]=u;
ins[u]=1;
int i,k;
for(i=head[u];i;i=e[i].next)
{
k=e[i].to;
if(!dfn[k])
{
tar(k);
low[u]=min(low[u],low[k]);
}
else if(ins[k])
low[u]=min(low[u],dfn[k]);
}
if(dfn[u]==low[u])
{
sn++;  // 强连通分支
do
{
k=sta[top--];
ins[k]=0;
col[k]=sn; // 染色
}
while(k!=u);
}
}
void dfs(int u)
{
vis[u]=1;
int i,k;
for(i=head[u];i;i=e[i].next)
{
k=e[i].to;
if(!vis[k])
dfs(k);
sta[++top]=u;
}
}
int main()
{
int i,k,flag,a,b;
char c[2],d[2];
while(scanf("%d%d",&n,&m),n||m)
{
top=ti=sn=0; tot=1;
clr(head); clr(ins); clr(dfn);  clr(low); clr(col);
while(m--)
{
scanf("%d%s%d%s",&a,c,&b,d);
a=2*a;
if(c[0]=='h')
a+=1;
b=2*b;
if(d[0]=='h')
b+=1;
add(2*a+1,2*b);
add(2*b+1,2*a);
}
for(i=0;i<n;i++)
{
add(4*i,4*i+3);
add(4*i+3,4*i);
add(4*i+1,4*i+2);
add(4*i+2,4*i+1);
}
add(2,3); // 新郎,新娘
for(i=0;i<4*n;i++)
if(dfn[i]==0)
tar(i);
for(i=0;i<4*n;i+=2)
{
if(col[i]==col[i+1])
break;
}
if(i!=4*n)
{
printf("bad luck\n");
continue;
}
top=0;
clr(vis);
clr(col);
for(i=0;i<4*n;i++)
if(!vis[i])
dfs(i);
while(top)
{
k=sta[top--];
if(col[k])
continue;
col[k]=2;
col[k^1]=1;
}
flag=0;
for(i=4;i<4*n;i+=2)
{
if(col[i]==2)
continue;
if(flag)
printf(" ");
flag=1;
printf("%d",i/4);
if(i%4>=2)
printf("h");
else printf("w");
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: