题目:

给定一个大小为 N×M 的迷宫。迷宫由通道和墙壁组成,每一步可以向邻接的上下左右四格

的通道移动。请求出从起点到终点所需的最小步数。请注意,本题假定从起点一定可以移动

到终点。

限制条件;N, M ≤ 100

测试样例:

N=10, M=10(迷宫如下图所示。 '#', '.', 'S', 'G'分别表示墙壁、通道、起点和终点)

#S######.#
......#..#
.#.##.##.#
.#........
##.##.####
....#....#
.#######.#
....#.....
.####.###.
....#...G#

输出结果:

22

关于深度优先搜索我在之前的博客中有提及:深度优先搜索初尝试

以及小z的房子

那么这道题目能不能用深度优先搜索解决呢?

很遗憾,深度优先搜索做不到。

在经过三次尝试以后,得出了DFS解此题的几大缺陷

  • 1.深度优先搜索,顾名思义,对一条可能的路径搜索至无法在搜索,再对下一条路径进行搜索。那么当利用栈来进行DFS搜索,记录最短路径的步数,怎么实现?就算你把已经搜索过的位置标记,再利用标记来减去多余的步数,实现的语句也是非常亘长和麻烦的。
  • 2.那么我用队列来存储可以吗?在第一点,大部分实现DFS算法都是利用栈,那么也带来了一定的麻烦,你经过的每一点都被压入栈中,并且因为栈的后进先出(LIFO),导致每一次搜索分支结束以后,返回的时候(如果没有找到终点),都需要退栈。如果使用队列的话就不会这么麻烦。

    那么用队列实现的“特别的”DFS算法,能不能行的通?答案也是否定的,原因也是因为记录最短路径的步数问题,每次压入队列都有多个坐标。读者可以自己画一个队列进行模拟。
  • 3.DFS搜索到的路径未必是最短的。如果有两条路径可以抵达终点,那么DFS最初所选择的路径未必是最短的。

用BFS(queue)来实现:

代码:

#include<cstdio>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<queue>
#define INF 1000;//定义INF;
using namespace std;
struct p
{
int x,y;
};//存储坐标 int k;
int n,m; int change[6][3]={{1,0},{-1,0},{0,1},{0,-1}};
char pla[105][105];
int dpla[105][105];//存储每一点距离的数组 void BFS(int beginx,int beginy)
{
int i,j;
queue<p>q;//存储坐标的队列 p begin,between;
begin.x=beginx;
begin.y=beginy; q.push(begin); for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
dpla[i][j]=INF;//所有位置的距离初始化为INF;
}
} dpla[begin.x][begin.y]=0;//开始的地方设置为0;
pla[begin.x][begin.y]='z';//用'z'替换掉原来的‘.’防止走回去 while(!q.empty())
{
begin=q.front();//取出队首开始搜索
q.pop();
if(pla[begin.x][begin.y]=='g')break;//遇到终点break; for(i=0;i<4;i++)
{
between.x=begin.x+change[i][0];
between.y=begin.y+change[i][1];//上下左右搜索 if(between.x>0 && between.x<=n && between.y>0 && between.y<=m)
{
if(pla[between.x][between.y]=='.')
{
q.push(between);//入列
//在dpla记录每一个坐标的距离
dpla[between.x][between.y]=dpla[begin.x][begin.y]+1; pla[between.x][between.y]='z';//字符替换,声明已经走过
}
if(pla[between.x][between.y]=='G')//遇到终点
{
q.push(between);//终点入列;
//记录至终点的距离
dpla[between.x][between.y]=dpla[begin.x][begin.y]+1; pla[between.x][between.y]='g';//用g替换G,代表搜索到终点;
}
}
} } } int main()
{
int i,j;
scanf("%d%d",&n,&m); getchar();//回车
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
scanf("%c",&pla[i][j]);
}
getchar();
} for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(pla[i][j]=='S')//找到出发点;
BFS(i,j);
}
} //下面注释的代码判断距离有没有出错
/*for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
printf("%d ",dpla[i][j]);
}
printf("\n");
}*/ for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(pla[i][j]=='g')
printf("%d",dpla[i][j]);//输出终点记录的距离;
}
} return 0;
}

主要注意的地方和变量的名称我在代码中作了注释。写起来其实和DFS差不多,一个明显不同的地方就是用了一个数组dpla存储每一个坐标与原点坐标的距离。

我在敲这段程序的时候,犯了一个错误:忘记对搜索过的区域.进行字符的替换,这样会导致循环无法结束。

昭锡对BFS也有作一篇文章:迷宫问题

关于DFS和BFS深入的理解及其他:BFS和DFS算法介绍与实现 作者:yousheng324。

2016/3/16

BFS-迷宫问题-用宽度(广度)优先搜索解决最优路径问题的更多相关文章

  1. 【算法入门】广度/宽度优先搜索(BFS)

    广度/宽度优先搜索(BFS) [算法入门] 1.前言 广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历策略.因为它的思想是从一个顶点V0开始,辐射状地优先遍历其周围较 ...

  2. 层层递进——宽度优先搜索(BFS)

    问题引入 我们接着上次“解救小哈”的问题继续探索,不过这次是用宽度优先搜索(BFS). 注:问题来源可以点击这里 http://www.cnblogs.com/OctoptusLian/p/74296 ...

  3. 搜索与图论②--宽度优先搜索(BFS)

    宽度优先搜索 例题一(献给阿尔吉侬的花束) 阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫. 今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔 ...

  4. 【BFS宽度优先搜索】

    一.求所有顶点到s顶点的最小步数   //BFS宽度优先搜索 #include<iostream> using namespace std; #include<queue> # ...

  5. BFS算法的优化 双向宽度优先搜索

    双向宽度优先搜索 (Bidirectional BFS) 算法适用于如下的场景: 无向图 所有边的长度都为 1 或者长度都一样 同时给出了起点和终点 以上 3 个条件都满足的时候,可以使用双向宽度优先 ...

  6. 算法基础⑦搜索与图论--BFS(宽度优先搜索)

    宽度优先搜索(BFS) #include<cstdio> #include<cstring> #include<iostream> #include<algo ...

  7. 深度优先dfs与广度bfs优先搜索总结+例题

    DFS(Deep First Search)深度优先搜索 深度优先遍历(dfs)是对一个连通图进行遍历的算法.它的思想是从一个顶点开始,沿着一条路一直走到底,如果发现不能到达目标解,那就返回到上一个节 ...

  8. 宽度优先搜索--------迷宫的最短路径问题(dfs)

    宽度优先搜索运用了队列(queue)在unility头文件中 源代码 #include<iostream>#include<cstdio>#include<queue&g ...

  9. 挑战程序2.1.5 穷竭搜索>>宽度优先搜索

    先对比一下DFS和BFS         深度优先搜索DFS                                   宽度优先搜索BFS 明显可以看出搜索顺序不同. DFS是搜索单条路径到 ...

随机推荐

  1. iOS中Date和NString的相互转换

    必须知道的内容 G: 公元时代,例如AD公元     yy: 年的后2位     yyyy: 完整年     MM: 月,显示为1-12     MMM: 月,显示为英文月份简写,如 Jan      ...

  2. JAVA包装类介绍(一)(包装类、基本类型数据)

     1. 包装类把基本类型数据转换为对象      1.1每个基本类型在java.lang包中都有一个相应的包装类  2.包装类有何作用 2.1 提供了一系列实用的方法 2.2集合不允许存放基本数据类型 ...

  3. bootstrap modal插件弹出窗口如何限制最大高度,并且在内容过多时可以滚动显示

    .modal-body{ max-height:400px; overflow-y:auto; } 只有在modal-body类上限制高度才能起作用,其他地方的限制均不起作用

  4. Hive学习笔记:基础语法

    Hive基础语法 1.创建表 – 用户表 CREATE [EXTERNAL外部表] TABLE [IF NOT EXISTS 是否存在] HUserInfo ( userid int comment ...

  5. Locust性能测试1-环境准备与基本使用

    前言 提到性能测试,大部分小伙伴想到的就是LR和jmeter这种工具,小编一直不太喜欢写这种工具类的东西,我的原则是能用代码解决的问题,尽量不去用工具. python里面也有一个性能测试框架Locus ...

  6. 《Enhanced LSTM for Natural Language Inference》(自然语言推理)

    解决的问题 自然语言推理,判断a是否可以推理出b.简单讲就是判断2个句子ab是否有相同的含义. 方法 我们的自然语言推理网络由以下部分组成:输入编码(Input Encoding ),局部推理模型(L ...

  7. mac下安装了brew

    使用mac后发现很多软件都可以通过终端命令brew...来安装. 查了一下,发现brew原来是osx系统上的软件包管理工具,全名是Homebrew,官网:https://brew.sh(这官竟然还包含 ...

  8. wkhtmtopdf--高分辨率HTML转PDF(二)

    命令行 wkhtmtopdf有一些很实用的命令,平时如果不用代码,可以直接使用命令行来把你喜欢的任意网页转换为PDF, 命令行参考网址:http://madalgo.au.dk/~jakobt/wkh ...

  9. python多进程打印字符,加锁(Lock加锁)

    先看不加锁的: #coding=utf-8from multiprocessing import Process,Lockimport time def l(num):    #lock.acquir ...

  10. linux服务器---squid缓存

    Squid缓存 代理服务器会在本地硬盘设置缓存,这样可以提高网络效率 1修改squid配置文件“/etc/squid/squid.conf”,参数“cache_dir_ufs”就是设置缓存目录的 [r ...