DFS入门题--迷宫问题--详细--用于自我记录

本题目来源取自网络。
题目补充:只能走上下左右四个方向,不能斜向走;
输入(行m,列n,行列的数字,起点坐标,终点坐标)
5 4
1 1 2 1
1 1 1 1
1 1 2 1
1 2 1 1
1 1 1 2
1 1 4 3
输出:7
DFS简述
“不到南墙不回头”,从当前点往下搜索,如果满足条件,标记满足点为搜索过,则以满足条件的点为起点继续搜索,直到不满足条件,则一直回退到与满足条件的点的相邻的,且未被搜索过的点,继续重复上述操作。
当然这只是我个人理解,更多以及更好的DFS原理详解,参考百度。

回溯的个人基本理解
在DFS结束后,如果还想再次使用路径上的点作为新的路径中的一个点,则在DFS结束后,要将标记的点取标,以便于新端点的搜索。
题目分析
dfs的基本判断
判断终止与进行条件:

  • 当前格子不是空地 || 当前格子越界 则返回return;
  • 当前格子是终点,执行对应语句块,return;
  • 当前格子是空地 && 当前格子没被访问过 执行语句块XXXXX

假设从起点(1,1)出发,对起点的相应的四个方向进行搜索,现在规定以右方向为初始搜索方向,顺时针搜索:右->下->左->上
开始搜索的计算机思路(大白话):
从(1,1)向右搜索,(1,2)为空地,满足搜索的条件,步长+1,则标记该点走过,同时以(1,2)为起点继续搜索;
从(1,2)向右搜索,(1,3)为障碍物,步长+1,不满足搜索的条件,则执行第一个终止条件中的语句,接着return。此时return回去的语句是以(1,2)为起点的搜索情况,结束的是以向右搜索的情况。按照一开始设定的搜索思路,顺时针搜索,接下来是向下搜索。
从(1,2)向下搜索,(2,2)为空地且未被访问过,满足搜索的条件,步长+1,则标记该点走过,同时以(2,2)为起点继续搜索;
从(2,2)向右搜索,(2,3)为空地且未被访问过,满足搜索的条件,步长+1,则标记该点走过,同时以(2,3)为起点继续搜索;
从(2,3)向右搜索,(2,4)为空地且未被访问过,满足搜索的条件,步长+1,则标记该点走过,同时以(2,4)为起点继续搜索;
从(2,4)向右搜索,(2,5)超出范围了,不满足搜索的条件,return到(2,4)搜索情况。
接着从(2,4)向下搜索,(3,4)为空地且未被访问过,满足搜索的条件,步长+1,则标记该点走过,同时以(3,4)为起点继续搜索;
从(3,4)开始搜索,向右,不成立,跳出,向下,成立,则标记,同时步数加1。
接着从(3,5)开始搜索,顺时针搜索到了终点,标记,步长+1;
此刻结束了的步长为7.
以上是一条路径的搜索的全过程。
接下来是讲回溯的过程。
那么到达终点以后,此刻对应的点都被标记,为了便于理解,我画了简图。
1绿色为标记,红色为步数,黑色为路径
那么接下来开始回溯:
从终点开始回溯,删除终点的标记点,返回到步长为6的点,继续以(4,4)为起点开始搜索,因为(4,4)到终点是向左搜索所以,按照顺时针的搜索方式,下一个点向上搜索,但是由于(3,4)已经标记过了,所以return。
这时候到了步长为5的点(3,4),因为(4,4)是(3,4)向下搜索的情况,返回后,继续顺时针搜索,则向右搜索,(3,3)是障碍物,所以return,接下来向上搜索,是
标记过的点,所以return到了(2,4)的搜索情况。
接下来依次这样执行直到(2,2)这个点搜索情况
下面是另外的路径情况在这里插入图片描述在这里插入图片描述其实到这里,题目已经差不多做完了。还需要对每条路径的长度进行比较,选出最短的进行输出,即为答案。
源代码如下:

#include<iostream>
using namespace std;
int m,n,p,q,MIN=9999;//m为行,n为列,pq分别为终点xy坐标,MIN最短步数; 
int a[105][105]; //地图数组 
int visit[105][105];//访问数组,用来标记 
int dx[4]={0,1,0,-1};//对应的右下左上的x的位移 
int dy[4]={1,0,-1,0};//对应的右下左上的y的位移 
void dfs(int x,int y,int step)
{
	if (x<0||x>m||y<0||y>n||visit[x][y]==1)return ;//数组越界或者被标记了
	if(x==p && y==q)//如果是终点,判断当前路径的步数是否最小 
	{
		if(step<MIN)MIN=step;
		return ;
	}
	for(int i=0;i<4;i++)
	{
		int tx=x+dx[i];
		int ty=y+dy[i];
		if(a[tx][ty]==1&&visit[tx][ty]==0)
		{
			visit[tx][ty]=1;//标记当前搜索的点为已访问 
			dfs(tx,ty,++step);//以当前这个点为起点继续搜索 
			visit[tx][ty]=0;//搜索完以后,回溯,取消该点的访问。 
		}
	}
}
int main()
{
	int startx,starty;
	cin>>m>>n;
	for(int i=1;i<=m;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
		}		
	}
	cin>>startx>>starty;//输入起点坐标 
	cin>>p>>q;//输入终点坐标 
	visit[startx][starty]=1;//起始位置标记走过 
	dfs(startx,starty,0);//从起点坐标开始搜索 
	cout<<MIN;
	return 0;
}

做了这题,是我的DFS真正的一次入门,写这篇博客,用来记录一下。如果对你们有帮助,欢迎一起学习。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

澄澈i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值