解救小哈——DFS算法举例
一、问题引入
有一天,小哈一个人去玩迷宫。但是方向感不好的小哈很快就迷路了。小哼得知后便去解救无助的小哈。此时的小哼已经弄清楚了迷宫的地图,现在小哼要以最快的速度去解救小哈。那么,问题来了...
二、问题的分析
首先我们用一个二维数组来存储这个迷宫,刚开始的时候,小哼处于迷宫的入口处(1,1),小哈在(p,q)。其实这道题的的本质就在于找从(1,1)到(p,q)的最短路径。
此时摆在小哼面前的路有两条,我们可以先让小哼往右边走,直到走不通的时候再回到这里,再去尝试另外一个方向。
在这里我们规定一个顺序,按照顺时针的方向来尝试(即右→下→左→上)。
我们先来看看小哼一步之内可以到达的点有哪些?只有(1,2)和(2,1)。
根据刚才的策略,我们先往右边走,但右边(1,3)有障碍物,所以只能往下(2,2)这个点走。但是小哈并不在(2,2)这个点上,所以小哼还得继续往下走,直至无路可走或者找到小哈为止。
注意:并不是让我们找到小哈此题就解决了。因为刚才只是尝试了一条路的走法,而这条路并不一定是最短的。刚才很多地方在选择方向的时候都有多种选择,因此我们需要返回到这些地方继续尝试往别的方向走,直到把所有可能都尝试一遍,最后输出最短的一条路径。
例如下图就是一条可行的搜索路径:
三、解决问题——深度优先搜索
(1)如何写dfs函数。
dfs函数的功能是解决当前应该怎么办。而小哼处在某个点的时候需要处理的是:先检查小哼是否已经到达小哈的位置,如果没有到达则找出下一步可以走的地方。
为了解决这个问题,此处dfs()函数只需要维护三个参数,分别是当前这个点的x坐标,y坐标以及当前已经走过的步数step。
//dfs函数定义如下: void dfs(int x,int y,int step) {return 0; }
(2)判断是否已经到达小哈的位置。
只需要判断当前的坐标是否与小哈的坐标相等就可以了,如果相等就标明已经到达小哈的位置。
void dfs(int x,int y,int step) {if(x==p && y==q) //判断是否到达小哈的位置 {if(step<min)min=step; //更新最小值return; //这步很重要! }return 0; }
(3)如何获得下一个方向的坐标(此处定义一个方向数组)。
int next[4][2]={{0,1},//向右走{1,0},//向下走{0,-1},//向左走{-1,0},//向上走 };
通过这个方向数组,使用循环就可以方便地得到下一步的坐标。
这里将下一步的横坐标用tx存储,纵坐标用ty存储。
for(k=0;k<=3;k++){/*计算下一个点的坐标*/tx=x+next[k][0];ty=y+next[k][1];}
(4)对下一个点(tx,ty)进行判断(是否越界,是否有障碍物,是否已经在路径中)。
在这里我们用book[tx][ty]来记录格子[tx][ty]是否已经在路径中。
如果这个点符合所有的要求,就对这个点进行下一步的扩展,即dfs(tx,ty,step+1)。
注意这里是step+1,因为一旦从这个点开始继续往下尝试,就意味着步数已经增加了1。
for(k=0;k<=3;k++){/*计算下一个点的坐标*/tx=x+next[k][0];ty=y+next[k][1];if(tx<1 || tx>n || ty<1 || ty>m) //判断是否越界continue;/*判断该点是否为障碍物或者已经在路径中*/if(a[tx][ty]==0 && book[tx][ty]==0){book[tx][ty]=1; //标记这个点已经走过dfs(tx,ty,step+1); //开始尝试下一个点book[tx][ty]=0; //尝试结束,取消这个点的标记 } }
四、完整代码
#include<stdio.h> int n,m,p,q,min=99999999; int a[51][51],book[51][51]; void dfs(int x,int y,int step) {int next[4][2]={{0,1},//向右走{1,0},//向下走{0,-1},//向左走{-1,0},//向上走 };int tx,ty,k;if(x==p && y==q) //判断是否到达小哈的位置 {if(step<min)min=step; //更新最小值return; }/*枚举四种走法*/ for(k=0;k<=3;k++){/*计算下一个点的坐标*/tx=x+next[k][0];ty=y+next[k][1];if(tx<1 || tx>n || ty<1 || ty>m) //判断是否越界continue;/*判断该点是否为障碍物或者已经在路径中*/if(a[tx][ty]==0 && book[tx][ty]==0){book[tx][ty]=1; //标记这个点已经走过dfs(tx,ty,step+1); //开始尝试下一个点book[tx][ty]=0; //尝试结束,取消这个点的标记 } }return; } int main() {int i,j,startx,starty;scanf("%d %d",&n,&m); //读入n和m,n为行,m为列/*读入迷宫*/for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&a[i][j]);scanf("%d %d %d %d",&startx,&starty,&p,&q); //读入起点和终点坐标/*从起点开始搜索*/book[startx][starty]=1; //标记起点已经在路径中,防止后面重复走dfs(startx,starty,0); //第一个参数是起点的x坐标,以此类推是起点的y坐标,初始步数为0printf("%d",min); //输出最短步数return 0; }
五、写在最后
发明深度优先算法的是John E.Hopcroft 和 Robert E.Tarjan。他们并不是研究全排列或者迷宫问题时发明了这个算法。
1971~1972年,他们在斯坦福大学研究图的连通性(任意两点是否可以相互到达)和平面性(图中所有的边相互不交叉。在电路板上设计布线的时候,要求线与线不能交叉,这就是平面性的一个实际应用),发明了这个算法。他们也因此获得了1986年的图灵奖。
在授奖仪式上,当年全国象棋程序比赛的优胜者说他的程序用的就是深度优先搜索算法,这是以其制胜的关键。
通过本次学习,我明白了当我们遇到这种需要“分身”,需要不断尝试完成的事情时,可以尝试使用深度优先搜索算法,因为计算机的运算速度还是很强的,我们要借助他的优势,完成一些生活中比较繁琐重复的事情。
(注:文章内容源自 啊哈磊的《啊哈算法》——很有意思的一本算法入门书!)
解救小哈——DFS算法举例相关推荐
- 啊哈算法——万能的搜索——解救小哈DFS
迷宫由n行m列的单元格组成(n和m都小于50),每个单元格要么是空地,要么是障碍物.你的任务是帮助小哼找到一条从迷宫的起点通往小哈所在位置的最短路径. (障碍物不能走,且不可走到迷宫外) /*啊哈算法 ...
- 解救小哈(深度优先,广度优先)
题目描述: 有一天,小哈一个去玩迷宫.但是方向感很不好的小哈很快就迷路了.小哼得知后便立即去解救无助的小哈.小哼当然是有备而来,已经弄清楚了迷宫地图,现在小哼要以最快速度去解救小哈.问题就此开始了-- ...
- 啊哈算法-DFS解救小哈python版
DFS 啊哈算法-解救小哈 maze_map = [] n,m = map(int,(input()).split()) maze_map = [input().split() for i in ra ...
- 解救小哈(dfs)-->改编自《啊哈!算法》
[算法描述] 有一天,小哈一个人去玩迷宫.但是方向感不好的小哈很快就迷路了.小哼得知后便去解救无助的小哈.此时的小哼已经弄清楚了迷宫的地图,现在小哼要以最快的速度去解救小哈.那么,问题就此开始了... ...
- JAVA算法:解救小哈(JAVA版)
JAVA算法:解救小哈(JAVA版) 有一天,小哈一个人去玩迷宫.但是方向感不好的小哈很快就迷路了.小哼得知后便去解救无助的小哈.此时的小哼已经弄清楚了迷宫的地图,现在小哼要以最快的速度去解救小哈.那 ...
- 解救小哈(dfs或bfs)
题目描述: 有一天,小哈一个人去玩迷宫.但是方向感很不好的小哈很快就迷路了.小哼得知后便立即去解救无助的小哈.小哼当然是有备而来,已经弄清楚了迷宫的地图,现在小哼要以最快的速度去解救小哈.问题就此开始 ...
- 《啊哈算法》学习五 解救小哈
通过一个解救小哈的游戏,来学习深度优化搜索算法. 规则如下: 小哈被困在终点,小哼从(1,1)出发去找小哈,每一步只能选择往上下左右走一格,不能走到锁所在地格子上,也不能走出图片限定的区域,求出小哼走 ...
- 宽搜 c语言,啊哈算法之宽搜BFS解救小哈
简述 本算法摘选自啊哈磊所著的<啊哈!算法>第四章第三节的题目--BFS算法再次解救小哈.文中代码使用C语言编写,博主通过阅读和理解,重新由Java代码实现了一遍,以此来理解BFS算法.关 ...
- 啊哈算法—解救小哈(广度优先搜索)
解救小哈 小哈在一个(m * n)大小的迷宫(0 ⇐ m, n ⇐ 50)里迷路了.在迷宫中,每个单元格要么是空地,要么是障碍物.现在要找到从起点到小哈位置的最短步数. 思路: 使用队列储存扩展,扩展 ...
最新文章
- javascript es6 箭头函数 简介
- 产品必懂技术术语(后台类)
- CentOS7中卸载Docker
- 大学校运会计算机专业方阵,校运动会方阵策划案
- D - Power Strings POJ - 2406
- java统计单机次数_java流类,快速统计出字符次数+++
- 汽车抛负载7637-5A/5B测试介绍
- retrofit + rxjava2报错java.lang.IllegalStateException:Excepted a String but was BEGIN_OBJECT at line..
- 关于o1,o2,o3
- L9954LXP_特殊功能,车门模块驱动器
- 基于babylon3D模型研究3D骨骼动画(1)
- 详解ARM的AMBA设备中的DMA设备(Linux驱动之DMA)
- Windows11电脑触摸屏不能用怎么修复
- 自由运动物体的运动代码
- CPU温度过高会导致电脑死机么
- shell中各种括号的作用详解()、(())、[]、[[]]、{}(推荐)
- TCP/IP协议详解篇一(基础)
- 【模拟电路】关于NPN和PNP导通的应用以及条件
- 2021-07-25
- 在托马斯·哈代的五月中学习机器学习之新闻分类
热门文章
- 【转载】超简单集成HMS ML Kit 人脸检测实现可爱2D贴纸
- 计算机软件知识产权的范围,知识产权包括的范围是什么
- 1、ipywidgets
- 【车间调度】FJSP的属性模型符号约定和约束条件
- 0-SIM卡的迭代(SIM-USIM-eSIM-vSIM-softSIM)
- 【大学生数学建模竞赛时间一览表】
- 电脑上有什么比较好用的屏幕录制软件
- QQ邮箱获取和使用授权码
- 水星路器服务器无响应,联想M720Q、光网卡、Pon stick、Openwrt我的完美软路由折腾记...
- Hibernate:DisjunctionConjunction构造复杂的查询条件