2024年寒假算法班集训day08-知识总结及题解(深搜上)

概念

深度优先搜索(DFS)是一种用于遍历或搜索树或图的结构的算法。它沿着一个路径深入遍历直到末端,然后回溯至最近的分叉点再继续其他路径的遍历,这个过程持续进行直到所有的顶点都被访问过。DFS常常用递归来实现,易于编码,同时也可以手动使用栈来模拟递归过程。在二叉树中,DFS可以用来实现前序、中序、后序遍历。它的应用包括寻找连通分量、拓扑排序以及解决一些组合问题。

1、统计路线-2935

在这里插入图片描述
题目描述了一个迷宫探宝问题。迷宫是一个 (N \times N) 的方格,其中“0”表示可以通行的格子,“1”表示不可通行的障碍,“2”表示宝藏的位置。从左上角的位置 (1,1) 开始,要求找到所有能够到达宝藏位置的路径数量。每个格子只能经过一次,且第一个格子不能是“1”。

输入描述:

  • 第一行是一个正整数 (N),表示迷宫是 (N \times N) 的方格。
  • 接下来的 (N \times N) 行,每行包含由“0”、“1”、“2”组成的序列,分别表示每个格子的状态。

输出描述:

  • 输出是一个整数,表示可以找到宝藏的所有不同路径的数量。

样例输入输出解释:

例如,对于一个5x5的迷宫样例:

5
0 0 1 1 0
1 0 0 0 0
0 0 0 0 2
0 1 1 0 0
0 0 0 1 0

一共有12条不同的路径可以从起点到达宝藏。

代码解析:

首先定义了一个迷宫数组 mp 和一个访问标记数组 vis,以及两个全局变量 ans(用来计数所有可能的路径)和 n(表示迷宫的大小)。dxdy 两个数组定义了在迷宫中移动的四个方向(右、下、左、上)。

void dfs(int x,int y){
   
    // ...
}

dfs 函数是深度优先搜索的实现,它尝试从当前位置 (x, y) 探索所有可能的路径。如果当前位置是宝藏,则路径计数加一并返回;否则,它将尝试移动到四个可能的方向上的下一个位置,如果下一个位置在迷宫内、不是障碍并且未被访问过,则进入下一个位置并继续搜索。

主函数 main 读取迷宫的大小和布局,如果起始位置是障碍,则直接输出0;否则,从起始位置开始调用 dfs 函数进行搜索,最终输出找到的宝藏路径总数。

性能考量:

由于迷宫的大小限制在 (10 \times 10) 以内,这个深度优先搜索算法在性能上是可接受的。尽管在最坏情况下,可能的路径数量可能会非常大,但由于路径上的每个格子只能访问一次,所以实际的搜索空间相对较小。

示例输出解释:

对于第二个样例输入:

2
0 0
0 2

输出为2,表示存在两条路径可以到达宝藏。

#include<iostream>
using namespace std;
int mp[10][10]={
   };//地图
bool vis[10][10]={
   };//记录是否访问过
int dx[4]={
   0,1,0,-1},dy[4]={
   1,0,-1,0};//右下左上
int ans=0,n;//ans:统计线路 n:n*n的地图
void dfs(int x,int y){
   
	if(mp[x][y]==2){
   //找到宝藏
		ans++;//累加线路
		return ;//返回到上一个方格
	}
	for(int i=0;i<4;i++){
   //遍历四个方向
		int nx=x+dx[i];//下一个方格的行下标
		int ny=y+dy[i];//下一个方格的列下标
		if(nx>0&&nx<=n && ny>0&&ny<=n){
   //在地图内
			if(mp[nx][ny]!=1 && vis[nx][ny]==0){
   //方格不是假山同时没有访问过
				vis[nx][ny]=1;//当前方格标记访问过
				dfs(nx,ny);//重复上述步骤
				vis[nx][ny]=0;//递归返回到当前房间,当前房间标记为0(回溯)
			}
		}
	}
}
int main(){
   
	cin>>n;//地图大小
	for(int i=1;i<=n;i++){
   //生成地图
		for(int j=1;j<=n;j++)
			cin>>mp[i][j];
	}
	if(mp[1][1]==1){
   //第一个方格为1,有0条路径
		cout<<0;//输出0
		return 0;//结束程序
	}
	vis[1][1]=1;//第一个方格访问过
	dfs(1,1);//深搜
	cout<<ans;//找到宝藏总线路
	return 0;
}

2、八个方向-2936

在这里插入图片描述
题目描述了一个通过迷宫寻宝的场景。迷宫由 (N \times N) 个房间组成,每个房间都可以通向周围的八个房间(允许对角线移动)。迷宫中有些房间被蝙蝠占据(用1表示),不能通过;有些房间是空的(用0表示),可以通过;还有一个房间藏有宝藏(用2表示)。起点位于 (1,1),且起点房间没有蝙蝠。需要判断是否存在一条路径可以从起点到达藏有宝藏的房间。

输入描述:

  • 第一行是一个正整数 (N) ((2 < N \leq 10)),表示迷宫的大小。
  • 接下来是一个 (N \times N) 的矩阵,矩阵中的数值用于表示迷宫房间的状态(0表示空房间,1表示有蝙蝠的房间,2表示有宝藏的房间)。

输出描述:

  • 如果可以找到宝藏,则输出 “YES”;如果找不到宝藏,则输出 “NO”。

样例输入输出解释:

例如,对于样例输入1:

6
0 0 1 1 0 0
1 0 0 1 0 0
0 0 0 1 2 0
0 1 1 1 0 0
0 0 0 1 0 0
0 0 0 1 0 0

由于宝藏被蝙蝠包围,没有办法到达宝藏的位置,所以输出 “NO”。

对于样例输入2:

5
0 0 0 0 0
0 0 1 1 1
0 0 0 1 0
0 1 0 1 2
0 0 0 0 1

存在一条路径可以避开蝙蝠,从 (1,1) 到达宝藏的位置,所以输出 “YES”。

代码解析:

定义了一个迷宫数组 mp 和一个访问标记数组 vis。数组 dxdy 分别存储了从当前房间移动到相邻房间的行和列的变化量(包括对角线移动)。flag 变量用来标记是否找到宝藏。

void dfs(int x, int y){
   
    // ...
}

dfs 函数是深度优先搜索的实现,用于探索迷宫。如果当前位置是宝藏,就设置 flagtrue 并返回。否则,函数会尝试访问当前位置周围的所有房间,除非房间中有蝙蝠或已经访问过。

main 函数中,读取迷宫的大小和布局,然后从起点开始调用 dfs 函数进行搜索。搜索完成后,根据 flag 的值输出结果。

性能考量:

给定的迷宫大小最大为 (10 \times 10),所以深度优先搜索在此问题上是可行的。即便最坏的情况下,可能的路径数量是大的,但由于每个房间只能访问一次,实际的搜索空间是有限的。

示例输出解释:

对于给定的迷宫,程序将执行深度优先搜索,并根据是否可以找到一条通往宝藏的路径来输出 “YES” 或 “NO”。

#include<iostream>
using namespace std;
int mp[11][11],n;
bool vis[11][11];
//上、右上、右、右下、下、左下、左、左上
int dx[8]={
   -1,-1,0,1,1,1,0,-1};
int dy[8]={
   0,1,1,1,0,-1,-1,-1};
bool flag=false;//flag表示是否找到宝箱,false:未找到
void dfs(int x,int y){
   
	if(mp[x][y]==2){
   //找到宝箱
		flag=true;//标记找到宝箱
		return ;
	}
	for(int i=0;i<8;i++){
   //遍历当前房间的八个方向
		int nx=x+dx[i];//下一个房间的行下标
		int ny=y+dy[i];//下一个房间的列下标
		if(nx>0&&nx<=n && ny>
  • 40
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值