HDU 2181-哈密顿绕行世界问题-dfs+链表树存路径

题目描述:

一个规则的实心十二面体,它的 20个顶点标出世界著名的20个城市,你从一个城市出发经过每个城市刚好一次后回到出发的城市。

输入描述:

前20行的第i行有3个数,表示与第i个城市相邻的3个城市.第20行以后每行有1个数m,m<=20,m>=1.m=0退出.

输出描述:

输出从第m个城市出发经过每个城市1次又回到m的所有路线,如有多条路线,按字典序输出,每行1条路线.每行首先输出是第几条路线.然后个一个: 后列出经过的城市.参看Sample output

输入样例:

2 5 20
1 3 12
2 4 10
3 5 8
1 4 6
5 7 19
6 8 17
4 7 9
8 10 16
3 9 11
10 12 15
2 11 13
12 14 20
13 15 18
11 14 16
9 15 17
7 16 18
14 17 19
6 18 20
1 13 19
5
0

输出样例:

1:  5 1 2 3 4 8 7 17 18 14 15 16 9 10 11 12 13 20 19 6 5
2:  5 1 2 3 4 8 9 10 11 12 13 20 19 18 14 15 16 17 7 6 5
3:  5 1 2 3 10 9 16 17 18 14 15 11 12 13 20 19 6 7 8 4 5
4:  5 1 2 3 10 11 12 13 20 19 6 7 17 18 14 15 16 9 8 4 5
5:  5 1 2 12 11 10 3 4 8 9 16 15 14 13 20 19 18 17 7 6 5
6:  5 1 2 12 11 15 14 13 20 19 18 17 16 9 10 3 4 8 7 6 5
7:  5 1 2 12 11 15 16 9 10 3 4 8 7 17 18 14 13 20 19 6 5
8:  5 1 2 12 11 15 16 17 18 14 13 20 19 6 7 8 9 10 3 4 5
9:  5 1 2 12 13 20 19 6 7 8 9 16 17 18 14 15 11 10 3 4 5
10:  5 1 2 12 13 20 19 18 14 15 11 10 3 4 8 9 16 17 7 6 5
11:  5 1 20 13 12 2 3 4 8 7 17 16 9 10 11 15 14 18 19 6 5
12:  5 1 20 13 12 2 3 10 11 15 14 18 19 6 7 17 16 9 8 4 5
13:  5 1 20 13 14 15 11 12 2 3 10 9 16 17 18 19 6 7 8 4 5
14:  5 1 20 13 14 15 16 9 10 11 12 2 3 4 8 7 17 18 19 6 5
15:  5 1 20 13 14 15 16 17 18 19 6 7 8 9 10 11 12 2 3 4 5
16:  5 1 20 13 14 18 19 6 7 17 16 15 11 12 2 3 10 9 8 4 5
17:  5 1 20 19 6 7 8 9 10 11 15 16 17 18 14 13 12 2 3 4 5
18:  5 1 20 19 6 7 17 18 14 13 12 2 3 10 11 15 16 9 8 4 5
19:  5 1 20 19 18 14 13 12 2 3 4 8 9 10 11 15 16 17 7 6 5
20:  5 1 20 19 18 17 16 9 10 11 15 14 13 12 2 3 4 8 7 6 5
21:  5 4 3 2 1 20 13 12 11 10 9 8 7 17 16 15 14 18 19 6 5
22:  5 4 3 2 1 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5
23:  5 4 3 2 12 11 10 9 8 7 6 19 18 17 16 15 14 13 20 1 5
24:  5 4 3 2 12 13 14 18 17 16 15 11 10 9 8 7 6 19 20 1 5
25:  5 4 3 10 9 8 7 6 19 20 13 14 18 17 16 15 11 12 2 1 5
26:  5 4 3 10 9 8 7 17 16 15 11 12 2 1 20 13 14 18 19 6 5
27:  5 4 3 10 11 12 2 1 20 13 14 15 16 9 8 7 17 18 19 6 5
28:  5 4 3 10 11 15 14 13 12 2 1 20 19 18 17 16 9 8 7 6 5
29:  5 4 3 10 11 15 14 18 17 16 9 8 7 6 19 20 13 12 2 1 5
30:  5 4 3 10 11 15 16 9 8 7 17 18 14 13 12 2 1 20 19 6 5
31:  5 4 8 7 6 19 18 17 16 9 10 3 2 12 11 15 14 13 20 1 5
32:  5 4 8 7 6 19 20 13 12 11 15 14 18 17 16 9 10 3 2 1 5
33:  5 4 8 7 17 16 9 10 3 2 1 20 13 12 11 15 14 18 19 6 5
34:  5 4 8 7 17 18 14 13 12 11 15 16 9 10 3 2 1 20 19 6 5
35:  5 4 8 9 10 3 2 1 20 19 18 14 13 12 11 15 16 17 7 6 5
36:  5 4 8 9 10 3 2 12 11 15 16 17 7 6 19 18 14 13 20 1 5
37:  5 4 8 9 16 15 11 10 3 2 12 13 14 18 17 7 6 19 20 1 5
38:  5 4 8 9 16 15 14 13 12 11 10 3 2 1 20 19 18 17 7 6 5
39:  5 4 8 9 16 15 14 18 17 7 6 19 20 13 12 11 10 3 2 1 5
40:  5 4 8 9 16 17 7 6 19 18 14 15 11 10 3 2 12 13 20 1 5
41:  5 6 7 8 4 3 2 12 13 14 15 11 10 9 16 17 18 19 20 1 5
42:  5 6 7 8 4 3 10 9 16 17 18 19 20 13 14 15 11 12 2 1 5
43:  5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 2 3 4 5
44:  5 6 7 8 9 16 17 18 19 20 1 2 12 13 14 15 11 10 3 4 5
45:  5 6 7 17 16 9 8 4 3 10 11 15 14 18 19 20 13 12 2 1 5
46:  5 6 7 17 16 15 11 10 9 8 4 3 2 12 13 14 18 19 20 1 5
47:  5 6 7 17 16 15 11 12 13 14 18 19 20 1 2 3 10 9 8 4 5
48:  5 6 7 17 16 15 14 18 19 20 13 12 11 10 9 8 4 3 2 1 5
49:  5 6 7 17 18 19 20 1 2 3 10 11 12 13 14 15 16 9 8 4 5
50:  5 6 7 17 18 19 20 13 14 15 16 9 8 4 3 10 11 12 2 1 5
51:  5 6 19 18 14 13 20 1 2 12 11 15 16 17 7 8 9 10 3 4 5
52:  5 6 19 18 14 15 11 10 9 16 17 7 8 4 3 2 12 13 20 1 5
53:  5 6 19 18 14 15 11 12 13 20 1 2 3 10 9 16 17 7 8 4 5
54:  5 6 19 18 14 15 16 17 7 8 9 10 11 12 13 20 1 2 3 4 5
55:  5 6 19 18 17 7 8 4 3 2 12 11 10 9 16 15 14 13 20 1 5
56:  5 6 19 18 17 7 8 9 16 15 14 13 20 1 2 12 11 10 3 4 5
57:  5 6 19 20 1 2 3 10 9 16 15 11 12 13 14 18 17 7 8 4 5
58:  5 6 19 20 1 2 12 13 14 18 17 7 8 9 16 15 11 10 3 4 5
59:  5 6 19 20 13 12 11 10 9 16 15 14 18 17 7 8 4 3 2 1 5
60:  5 6 19 20 13 14 18 17 7 8 4 3 10 9 16 15 11 12 2 1 5

核心思想:

边搜边输出:

此题是dfs输出路径模板题,边搜边记录路径,到最内层输出即可。
见代码一。
但是这只适用于图稀疏,查询次数少的情况。复杂情况下预处理一下比较好。

预处理:

将全部路径预处理出来,用链表树存储,查哪个直接输出哪个就好。
枚举每一个点当作起点,dfs得到起点 i 的所有可行路径存于链表树path[i]中。每一次询问以m为起点的路径,dfs2搜索path[m],每到一个叶子结点就输出一次
见代码二。

代码一:

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=25;
int G[N][5],m;
int lu[N],cnt;
bool vis[N];
//将点x作为第k个点进行搜索 
void dfs(int k,int x)
{
	lu[k]=x;
	if(k==20)
	{
		//哈密顿回路要求路径首尾相连 
		if(G[x][1]==m||G[x][2]==m||G[x][3]==m)
		{
			printf("%d:  ",++cnt);
			for(int i=1;i<=20;i++)
				printf("%d ",lu[i]);
			printf("%d\n",m);
		}
		return;
	}
	vis[x]=1;
	//每个点都是个三岔路口
	for(int i=1;i<=3;i++)
		if(!vis[G[x][i]])
			dfs(k+1,G[x][i]);
	vis[x]=0;
	return;
}
int main()
{
	for(int i=1;i<=20;i++)
		for(int j=1;j<=3;j++)
			scanf("%d",&G[i][j]);
	while(1)
	{
		scanf("%d",&m);
		if(!m)
			break;
		cnt=0;
		dfs(1,m);
	}
	return 0;
}

代码二:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std;
typedef long long ll;
const int N=1e3+10;
//邻接表存边 
struct node{
	int y,ne;
}side[N];
//用第i棵链表树存从i点出发的全部路径 
struct Node{
	int x;
	Node *ne[3];
}path[N];
//用于邻接表
int head[N],cnt;
int vis[N];//标记此点是否走过
int ans[N],z;//用于输出一条路
//邻接表向图中加边 
void add(int x,int y)
{
	side[cnt].y=y;
	side[cnt].ne=head[x];
	head[x]=cnt++;
	return;
}
//深搜得到所有可行路径,返回空指针代表此路不通,否则此路可行 
Node* dfs(int st,int x)
{
	vis[x]=1;
	//初始化x这个岔路 
	Node *p=(Node*)malloc(sizeof(Node));
	p->x=x;
	//c遍历3个相邻的点,flag标记此点是否与起点相邻 
	int c=0,flag=0;
	for(int i=head[x];i!=-1;i=side[i].ne)
	{
		//tx为下一个点 
		int tx=side[i].y;
		//此点与起点相邻 
		if(tx==st)
			flag=1;
		if(!vis[tx])//未走过,可以走 
			p->ne[c++]=dfs(st,tx);
		else//不可以走,记为空指针 
			p->ne[c++]=NULL;
	}
	vis[x]=0;
	//相邻的三个点至少有一个可行,则此点可行 
	for(int i=0;i<3;i++)
		if(p->ne[i])
			return p;
	//相邻的三个点都不可行,判断此点是否为最后一个点 
	if(flag)//因为哈密顿回路要回到起点,所以要求此点与起点相邻 
	{
		for(int i=1;i<=20;i++)//哈密顿回路要求所有点走且只走一次 
			if(i!=x&&!vis[i])//还有点未走过,此点不能当作最后一个点 
				return NULL;
		//满足哈密顿回路,此点是最后一个点 
		return p;
	}
	//此点无后继且不能当作最后一个点,此路不通 
	return NULL;
}
//已知起点m,遍历第m棵链表树,输出所有可行路径 
void dfs2(Node *p,int k)
{
	ans[k]=p->x;
	for(int i=0;i<3;i++)
		if(p->ne[i])
			dfs2(p->ne[i],k+1);
	//20个点齐了,到达树的叶子结点,输出此路径 
	if(k==20)
	{
		printf("%d: ",++z);
		for(int i=1;i<=20;i++)
			printf(" %d",ans[i]);
		printf(" %d\n",ans[1]);
		return;
	}
	return;
}
int main()
{
	int a[3],m;
	//初始化邻接表
	cnt=0; 
	for(int i=0;i<N;i++)
		head[i]=-1;
	//输入建图
	for(int i=1;i<=20;i++)
	{
		for(int j=0;j<3;j++)
			scanf("%d",&a[j]);
		sort(a,a+3);
		for(int j=2;j>=0;j--)
			add(i,a[j]);
	}
	//深搜得到20棵链表树 
	for(int i=1;i<=20;i++)
		path[i]=*dfs(i,i);
	//输出 
	while(1)
	{
		scanf("%d",&m);
		if(!m)
			break;
		z=0;
		dfs2(&path[m],1);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值