Poj 1428 Children's Dining【哈密顿路径】

Children's Dining
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 4479 Accepted: 664 Special Judge

Description

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

Source

POJ Monthly,anonymous

哈密顿通路(回路):

通过图的每个结点一次,且仅一次的通路(回路),就是哈密顿通路(回路). 

存在哈密顿回路的图是哈密顿图。

存在的充分条件:

图有n个顶点,如果图中任意两个不同的顶点的度数之和大于等于n,则图是哈密顿图

题意:

2*n 个小朋友围着一个圆桌吃饭,并且对于每个人,都至多有n-1 人和他关系不好,现在让你安排个顺序,使得所有的人都不会和关系不好的人相邻


题解:

首先意识到是回路问题,而且遍历每个顶点有且仅有一次,每条边最多使用一次,也就是哈密顿回路问题了,

题目说2*n 个小朋友,每个人最多有n-1个不能相邻的,也就是每个人可以相邻的顶点至少有n+1个,那个哈密顿回路必定存在!

输出一条满足条件的哈密顿路径


解题思路:

建立本题给出的图的反向图( 能相邻的关系图),然后就是套模板啊套模板.....


其实不太懂,完全对着模板敲....

还敲错了好几次.......


/*
http://blog.csdn.net/liuke19950717
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=505;
inline void reverse(int ans[],int s,int t)
{
	while(s<t)
	{
		swap(ans[s],ans[t]);
		++s;--t;
	}
}
void hamilton(int ans[],bool map[maxn][maxn],int n)
{
	int s=1,t,ansi=2;
	bool vis[maxn]={0};
	int i,j,w;
	for(i=1;i<=n;++i)
	{
		if(map[s][i])
		{
			break;
		}
	}
	t=i;
	vis[s]=vis[t]=1;
	ans[0]=s;ans[1]=t;
	while(1)
	{
		while(1)
		{
			for(i=1;i<=n;++i)
			{
				if(map[t][i]&&!vis[i])
				{
					ans[ansi++]=i;
					vis[i]=1;
					t=i;
					break;
				}
			}
			if(i>n)
			{
				break;
			}
		}
		w=ansi-1;
		i=0;
		reverse(ans,i,w);
		swap(s,t);
		while(1)
		{
			for(i=1;i<=n;++i)
			{
				if(map[t][i]&&!vis[i])
				{
					ans[ansi++]=i;
					vis[i]=1;
					t=i;
					break;
				}
			}
			if(i>n)
			{
				break;
			}
		}
		if(!map[s][t])
		{
			for(i=1;i<ansi-2;++i)
			{
				if(map[ans[i]][t]&&map[s][ans[i+1]])
				{
					break;
				}
				
			}
			w=ansi-1;
			++i;
			t=ans[i];
			reverse(ans,i,w);
		}
		if(ansi==n)
		{
			return;
		}
		for(j=1;j<=n;++j)
		{
			if(vis[j])
			{
				continue;
			}
			for(i=1;i<ansi-2;++i)
			{
				if(map[ans[i]][j])
				{
					break;
				}
			}
			if(map[ans[i]][j])
			{
				break;
			}
		}
		s=ans[i-1];
		t=j;
		reverse(ans,0,i-1);
		reverse(ans,i,ansi-1);
		ans[ansi++]=j;
		vis[j]=1;
	}
}
int main()
{
	int n,m;
	//freopen("shuju.txt","r",stdin);
	while(scanf("%d%d",&n,&m),n|m)
	{
		bool map[maxn][maxn]={0};
		for(int i=0;i<m;++i)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			map[a][b]=map[b][a]=1;
		}
		for(int i=1;i<=2*n;++i)
		{
			for(int j=1;j<=2*n;++j)
			{
				if(i==j)
				{
					continue;
				}
				map[i][j]=!map[i][j];
			}
		}
		int ans[maxn]={0};
		hamilton(ans,map,2*n);
		printf("%d",ans[0]);
		for(int i=1;i<2*n;++i)
		{
			printf(" %d",ans[i]);
		}
		printf("\n");
	} 
	return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值