SGU 122.The book (哈密顿回路)

题目描述

     有一群人从1到N标号,而且这群人中每个人的朋友个数不少于 (N+1)/2 个。

编号为1的人有一本其他人都想阅读的书。

写一个程序,找到一种传阅顺序使得书本只经过每个人手中一次,并且一个人只能将书本传给他的朋友,并且书本最后必须传回给第一个人。(注释:如果A是B的朋友,那么B一定是A的朋友)

输入

      第一行包含一个数字N。

接下来的有N行,第i行表示第i-1个人的朋友

输出

     如果不存在解决方案,则输出 'No solution' 。否则你将输出1行包含N+1个整数,表示传阅路径,由1开始、由1结尾。

输入样例

4

2 3

1 4

1 4

2 3

输出样例

1 3 4 2 1

 

 

 

 


 

Solution:

            每个人至少有(n+1)/2 个朋友,一定存在哈密顿回路.

            找到哈密顿路后,从1 的位置开始输出,最后再输出一个1.

 

code:

 

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define INF 1111
using namespace std;
bool edge[INF][INF];
int ans[INF], vis[INF];
int n, tol = 2, t, s = 1;
void expand() {
	int i;
	while (1) {
		for (i = 1; i <= n; i++) {
			if (edge[t][i] && !vis[i]) {
				ans[tol++] = i;
				t = i, vis[i] = 1;
				break;
			}
		}
		if (i > n) return;
	}
}
void Hamiton() {
	int i, j;
	for (i = 1; i <= n; i++) if (edge[s][i]) break;
	t = i;
	ans[0] = s, ans[1] = t;
	vis[s] = vis[t] = 1;
	while (1) {
		expand();
		reverse (ans, ans + tol);
		swap (s, t);
		expand();
		if (!edge[s][t]) {
			for (i = 1; i < tol - 2; i++)
				if (edge[ans[i]][t] && edge[ans[i + 1]][s]) break;
			reverse (ans + i + 1, ans + tol);
			t = ans[tol - 1];
		}
		if (tol == n) return;
		for (j = 1; j <= n; j++) {
			if (vis[j]) continue;
			for (i = 1; i < tol - 1; i++)
				if (edge[ans[i]][j])	break;
			if (edge[ans[i]][j]) break;
		}
		s = ans[i - 1], t = j;
		reverse (ans, ans + i);
		reverse (ans + i, ans + tol);
		ans[tol++] = j, vis[j] = 1;
	}
}
int main() {
	char ci;
	scanf ("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf ("%d", &t);
		edge[i][t] = edge[t][i] = 1;
		ci = getchar();
		while (ci != '\n' && ci != '\r' && ci != EOF)
			scanf ("%d", &t), edge[i][t] = edge[t][i] = 1, ci = getchar();
	}
	Hamiton();
	int i;
	for (i = 0; i < n; i++)
		if (ans[i] == 1) break;
	for (int j = 0; j < n; j++) {
		printf ("%d ", ans[i]);
		i++;
		if (i == n) i = 0;
	}
	putchar ('0' + 1);
	return 0;
}

 

  

 

 

转载于:https://www.cnblogs.com/keam37/p/3835911.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值