您的位置:首页 > 其它

Children's Dining POJ2438 哈密顿图

2016-03-20 16:12 211 查看

题目描述:

Usually children in kindergarten like to quarrel with each other. This situation annoys the child-care women. For instant, when diner time comes, a fierce conflict may break out when a certain couple of children sitting side by side who are hostile with each other. Although there aren’t too many children dining at the same round table, but the relationship of “enemy” or “friend” may be very complex. The child-care women do come across a big problem. Now it is time for you to help them to figure out a proper arrangement of sitting, with which no two “enemy” children is adjacent.

Now we assume that there are 2 * n children who sit around a big table, and that none has more than n - 1 “enemies”.

输入输出:

Input

The input is consisted of several test blocks. For each block, the first line contains two integers n and m (1 <= n <= 200, 0 <= m <= n (n - 1)). We use positive integers from 1 to 2 * n to label the children dining round table. Then m lines followed. Each contains positive integers i and j ( i is not equal to j, 1 <= i, j <= 2 * n), which indicate that child i and child j consider each other as “enemy”. In a input block, a same relationship isn’t given more than once, which means that if “i j” has been given, “j i” will not be given.

There will be a blank line between input blocks. And m = n = 0 indicates the end of input and this case shouldn’t be processed.

Output

For each test block, if the proper arrangement exist, you should print a line with a proper one; otherwise, print a line with “No solution!”.

Sample Input

1 0

2 2
1 2
3 4

3 6
1 2
1 3
2 4
3 5
4 6
5 6

4 12
1 2
1 3
1 4
2 5
2 6
3 7
3 8
4 8
4 7
5 6
5 7
6 8

0 0


Sample Output

1 2
4 2 3 1
1 6 3 2 5 4
1 6 7 2 3 4 5 8


题目分析:

这道题的大意是有2*n个小孩,其中有m个敌对关系,这2*n个小孩需要排成一个圈,其相邻的人不能存在敌对关系,输出其任意一种可能的排列方式。

这道题是哈密顿图的模板题,刚看这道题我也不了解这道题的做法,之后发现这是一道哈密顿图的题,因为哈密顿图没有充要的判定条件,所以看上去判断是比较困难的。一起来学习一下这个特殊的图吧。

代码如下:

#include <iostream>
#include <string.h>
#include <stdio.h>

const int MAXN=410;
using namespace std;

int m,n;
bool map[MAXN][MAXN];
int ans[MAXN];
bool vis[MAXN];
int start,end;
int cnt;

void init()//初始化
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if (i==j) map[i][j]=0;
else map[i][j]=1;//没有敌对关系的点标记为1
}
}
memset(ans,0,sizeof(ans));
memset(vis,0,sizeof(vis));
cnt=0;
}

void reverse(int s,int e)//将ans数组中s到e的部分倒置
{
while(s<e)
{
swap(ans[s],ans[e]);
s++;
e--;
}
}

void kuozhan()//从end开始拓展
{
while(1)
{
int flag=0;
for(int i=1;i<=n;i++)
{
if(!vis[i] && map[end][i])
{
ans[cnt++]=i;
end=i;
vis[i]=1;
flag=1;
break;
}
}
if(!flag)
break;
}
}//将当前得到的序列倒置,s和t互换,从t继续扩展,相当于在原来的序列上从s扩展

void hamiltun()
{
start=1;//初始化start为1号点
for(int i=1; i<=n; i++)
{
if (map[1][i])
{
end=i;
break;
}
}
vis[start]=1;
vis[end]=1;
ans[0]=start;
ans[1]=end;
cnt=2;
while(1)
{
kuozhan();
reverse(0,cnt-1);
swap(start,end);
kuozhan();
int mid=0;
if(!map[start][end])//start end不相邻,调整
{
for(int i=1; i<cnt-2; i++)
{
if(map[ans[i]][end]&&map[ans[i+1]][start])//取序列中一点i,
//使ans[i]与end相连接,ans[i+1]与start相连
{
mid=i+1;
break;
}
}
reverse(mid,cnt-1);//将ans[mid]到ans[end-1]进行倒置
end=ans[cnt-1];
}
if(cnt==n)break;//当前序列中元素已经处理完毕 退出
for(int i=1; i<=n; i++)
{
if(!vis[i])
{
int j;
for(j=1; j<cnt-1; j++)
if(map[ans[j]][i])
{
mid=j;
break;
}
if(map[ans[mid]][i])
{
end=i;
mid=j;
break;
}
}
}
start=ans[mid-1];
reverse(0,mid-1);//从a[0]到ans[mid-1]倒置
reverse(mid,cnt-1);//倒置ans[mid]到ans[end-1]倒置
ans[cnt++]=end;//end点加入ans尾部
vis[end]=1;//标记已经处理的点
}
}

int main()
{
while(~scanf("%d%d",&n,&m))
{
if (!m && !n) break;
int u,v;
n*=2;
init();
for(int i=1; i<=m; i++)
{
scanf("%d%d",&u,&v);
map[u][v]=map[v][u]=0;//将有敌对关系的点标记为0
}
hamiltun();
printf("%d ",ans[0]);
for(int i=1;i<n;i++)
{
printf("%d ",ans[i]);
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: