题目描述:
一个规则的实心十二面体,它的 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;
}