欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PTA:7-117 地下迷宫探索 (30分)(dfs搜索加解析)

程序员文章站 2022-03-13 16:46:59
...

7-117 地下迷宫探索 (30分)

地道战是在抗日战争时期,在华北平原上抗日军民利用地道打击日本侵略者的作战方式。地道网是房连房、街连街、村连村的地下工事,如下图所示。
PTA:7-117 地下迷宫探索 (30分)(dfs搜索加解析)
我们在回顾前辈们艰苦卓绝的战争生活的同时,真心钦佩他们的聪明才智。在现在和平发展的年代,对多数人来说,探索地下通道或许只是一种娱乐或者益智的游戏。本实验案例以探索地下通道迷宫作为内容。
PTA:7-117 地下迷宫探索 (30分)(dfs搜索加解析)
假设有一个地下通道迷宫,它的通道都是直的,而通道所有交叉点(包括通道的端点)上都有一盏灯和一个开关。请问你如何从某个起点开始在迷宫中点亮所有的灯并回到起点?
输入格式:
输入第一行给出三个正整数,分别表示地下迷宫的节点数N(1<N≤1000,表示通道所有交叉点和端点)、边数M(≤3000,表示通道数)和探索起始节点编号S(节点从1到N编号)。随后的M行对应M条边(通道),每行给出一对正整数,分别是该条边直接连通的两个节点的编号。

输出格式:
若可以点亮所有节点的灯,则输出从S开始并以S结束的包含所有节点的序列,序列中相邻的节点一定有边(通道);否则虽然不能点亮所有节点的灯,但还是输出点亮部分灯的节点序列,最后输出0,此时表示迷宫不是连通图。

由于深度优先遍历的节点序列是不唯一的,为了使得输出具有唯一的结果,我们约定以节点小编号优先的次序访问(点灯)。在点亮所有可以点亮的灯后,以原路返回的方式回到起点。

输入样例1:
6 8 1
1 2
2 3
3 4
4 5
5 6
6 4
3 6
1 5

输出样例1:
1 2 3 4 5 6 5 4 3 2 1

输入样例2:
6 6 6
1 2
1 3
2 3
5 4
6 5
6 4

输出样例2:
6 4 5 4 6 0

思路:
该题困扰我的问题是,如何保存回溯的路径?
比如样例:
输入:

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

输出:

1 2 1 3 4 3 5 6 5 3 1

该样例画图如下:
PTA:7-117 地下迷宫探索 (30分)(dfs搜索加解析)
从该样例可以看出,题目要求的是输出完整的路径,也就是整个开灯的过程。
从1出发,按照小号优先,到达2,走不通了,又回到了1,再从1出发到达3,,,依次类推,完成。
具体过程见AC代码:

#include<bits/stdc++.h>
using namespace std;
int vis[1010],r[1010][1010],path[1010];
int n,m,s,j=0,cnt=1;  //cnt统计可以点亮的灯个数 

void dsf(int x){
	for(int i=1; i<=n; i++){
		if(r[x][i]&&!vis[i]){
			cnt++;
			vis[i]=1;
			
			//核心************* 
			path[j++]=i;//保存去的结点 
			dsf(i);
			path[j++]=x; //保存回去的路 
			//************* 
		} 
	}
} 
 
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>m>>s;
	while(m--){
		int a,b;
		cin>>a>>b;
		r[a][b]=1;
		r[b][a]=1;
	}
	path[j++]=s; 
	vis[s]=1;
	dsf(s);
	for(int i=0; i<j; i++){
		if(i!=0) cout<<" "; 
		cout<<path[i];
	}
	if(cnt<n) cout<<" 0"<<endl;
	return 0;
}

参考博客:https://blog.csdn.net/lyw_321/article/details/78105328
总结
通过该题,知道了做题时不用想的太麻烦(如果太麻烦的话,很有可能就是你的思路不是很好),发散一下思维,很难的问题可能也就两行代码。
另外就是,之前一直dfs都在return,这次使用了一次不带return的感觉很不错哦。
最后,自律才能更强。
欢迎大家批评改正!!!