问题引入

我们接着上次“解救小哈”的问题继续探索,不过这次是用宽度优先搜索(BFS)。

注:问题来源可以点击这里 http://www.cnblogs.com/OctoptusLian/p/7429645.html

最开始小哼在入口(1,1)处,一步之内可以到达的点有(1,2)和(2,1)。

但是小哈并不在这两个点上,那小哼只能通过(1,2)和(2,1)这两点继续往下走。

比如现在小哼走到了(1,2)这个点,之后他又能够到达哪些新的点呢?有(2,2)。再看看通过(2,1)又可以到达哪些点呢?可以到达(2,2)和(3,1)。

此时你会发现(2,2)这个点既可以从(1,2)到达,也可以从(2,1)到达,并且都只使用了两步。

注:为了防止一个点多次被走到,这里需要一个数组来记录一个点是否已经被走到过。

此时小哼2步可以走到的点就全部走到了,有(2,2)和(3,1),可是小哈并不在这两个点上。看来没有别的办法,还得继续往下尝试,看看通过(2,2)和(3,1)这两个点还能到达哪些新的没有走到过的点。

通过(2,2)这个点我们可以到达(2,3)和(3,2),通过(3,1)可以到达(3,2)和(4,1)。

现在三步可以到达的点有(2,3)、(3,2)和(4,1),依旧没有到达小哈的所在点,所以我们需要继续重复刚才的做法,直到找到小哈所在点为止。

解决步骤

回顾一下刚才的算法,可以用一个队列来模拟这个过程。在这里我们用一个结构体来实现队列

struct note{
int x; //横坐标
int y; //纵坐标
int s; //步数
};
struct note que[]; //因为地图大小不超过50*50,因此队列扩展不会超过2500个
int head,tail;
int a[][] = {}; //用来存储地图
int book[][] = {}; //数组book的作用是记录哪些点已经在队列中了,防止一个点被重复扩展,并全部初始化为0 /*最开始的时候需要进行队列初始化,即将队列设置为空*/
head = ;
tail = ;
//第一步将(1,1)加入队列,并标记(1,1)已经走过。
que[tail].x = ;
que[tail].y = ;
que[tail].s = ;
tail++;
book[][] = ;

然后从(1,1)开始,先尝试往右走到达了(1,2)。

tx = que[head].x;
ty = que[head].y+;

需要判断(1,2)是否越界。

if(tx <  || tx > n || ty <  || ty > m)
continue;

再判断(1,2)是否为障碍物或者已经在路径中。

if(a[tx][ty] ==  && book[tx][ty] == )
{
}

如果满足上面的条件,则将(1,2)入队,并标记该点已经走过。

book[tx][ty] = ;  //注意bfs每个点通常情况下只入队一次,和深搜不同,不需要将book数组还原
//插入新的点到队列中
que[tail].x = tx;
que[tail].y = ty;
que[tail].s = que[head].s+; //步数是父亲的步数+1
tail++;

接下来还要继续尝试往其他方向走。

在这里我们规定一个顺序,即按照顺时针的方向来尝试(右→下→左→上)。

我们发现从(1,1)还是可以到达(2,1),因此也需要将(2,1)也加入队列,代码实现与刚才对(1,2)的操作是一样的。

对(1,1)扩展完毕后,此时我们将(1,1)出队(因为扩展完毕,已经没用了)。

head++;

接下来我们需要在刚才新扩展出的(1,2)和(2,1)这两个点上继续向下探索(因为还没有到达小哈所在的位置,所以还需要继续)。

(1,1)出队之后,现在队列的head正好指向了(1,2)这个点,现在我们需要通过这个点继续扩展,通过(1,2)可以到达(2,2),并将(2,2)也加入队列。

(1,2)这个点已经处理完毕,于是可以将(1,2)出队。(1,2)出队之后,head指向了(2,1)这个点。通过(2,1)可以到达(2,2)和(3,1),但是因为(2,2)已经在队列中,因此我们只需要将(3,1)入队。

到目前为止我们已经扩展出从起点出发2步以内可以到达的所有点,可是依旧没有到达小哈所在的位置,因此还需要继续扩展,直到找到小哈所在的点才算结束。

为了方便向四个方向扩展,这里需要一个next数组:

int next[][] = {  //顺时针方向
{,}; //向右走
{,}; //向下走
{,-}; //向左走
{-,}; //向上走
}

完整代码如下

#include<stdio.h>
struct note{
int x; //横坐标
int y; //纵坐标
int f; //父亲在队列中的编号(本题不需要输出路径,可以不需要f)
int s; //步数
};
int main()
{
struct note que[]; //因为地图大小不超过50*50,因此队列扩展不会超过2500个 int a[][] = {}; //用来存储地图
int book[][] = {}; //数组book的作用是记录哪些点已经在队列中了,防止一个点被重复扩展,并全部初始化为0
//定义一个用于表示走的方向的数组
int next[][] = { //顺时针方向
{,}, //向右走
{,}, //向下走
{,-}, //向左走
{-,}, //向上走
}; int head,tail;
int i,j,k,n,m,startx,starty,p,q,tx,ty,flag; scanf("%d %d",&n,&m);
for(i=;i<=n;i++)
for(j=;j<=m;j++)
scanf("%d",&a[i][j]);
scanf("%d %d %d %d",&startx,&starty,&p,&q); //队列初始化
head = ;
tail = ;
//往队列插入迷宫入口坐标
que[tail].x = startx;
que[tail].y = starty;
que[tail].f = ;
que[tail].s = ;
tail++;
book[startx][starty] = ; flag = ; //用来标记是否到达目标点,0表示暂时没有到达, 1表示已到达
while(head < tail){ //当队列不为空时循环
for(k=;k<=;k++) //枚举四个方向
{
//计算下一个点的坐标
tx = que[head].x + next[k][];
ty = que[head].y + next[k][];
if(tx < || tx > n || ty < || ty > m) //判断是否越界
continue;
if(a[tx][ty] == && book[tx][ty] == ) //判断是否是障碍物或者已经在路径中
{
book[tx][ty] = ; //把这个点标记为已经走过。注意bfs每个点通常情况下只入队一次,和深搜不同,不需要将book数组还原
//插入新的点到队列中
que[tail].x = tx;
que[tail].y = ty;
que[tail].f = head; //因为这个点是从head扩展出来的,所以它的父亲是head,本题不需要求路径,因此可省略
que[tail].s = que[head].s+; //步数是父亲的步数+1
tail++; }
if(tx == p && ty == q) //如果到目标点了,停止扩展,任务结束,退出循环
{
flag = ; //重要!两句不要写反
break;
}
}
if(flag == )
break;
head++; //当一个点扩展结束后,才能对后面的点再进行扩展
}
printf("%d",que[tail-].s); //打印队列中末尾最后一个点,也就是目标点的步数
//注意tail是指向队列队尾(最后一位)的下一个位置,所以这里需要减1
getchar();getchar();
return ;
}

第一行有两个数n m,n表示迷宫的行数,m表示迷宫的列数。

接下来n行m列为迷宫,0表示空地,1表示障碍物。

最后一行四个数,前两个数表示迷宫入口的x和y坐标,后两个为小哈的x和y坐标。

写在最后

通过本次学习,我们知道一道问题的解决方法是多种多样的,不光可以用深度优先搜索来解,也可以用宽度优先搜索。

个人感觉宽度优先搜索就像是一次病原体的扩散,目的是要以最短的速度扩散到最广的范围。

注:文章内容源自《啊哈算法》

层层递进——宽度优先搜索(BFS)的更多相关文章

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

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

  2. 宽度优先搜索BFS(Breadth-First-Search)

    Breadth-First-Search 1. 与DFS的异同 相同点:搜索所有可能的状态. 不同点:搜索顺序. 2. BFS总是先搜索距离初始状态近的状态,它是按照:开始状态->只需一次转移就 ...

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

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

  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. 搜索与图论②--宽度优先搜索(BFS)

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

  8. [宽度优先搜索] FZU-2150 Fire Game

    Fat brother and Maze are playing a kind of special (hentai) game on an N*M board (N rows, M columns) ...

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

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

随机推荐

  1. (原创)C++11改进我们的程序之简化我们的程序(二)

    这次要讲的是:C++11如何通过组合函数来简化我们的程序.关于组合函数,大家可能对这个概念有点陌生.组合函数是将N个一元函数组成一种更复杂的函数,每个函数的返回值作为参数传给下一个函数,直到传到最后一 ...

  2. 【Acm】八皇后问题

    八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题. 其解决办法和我以前发过的[算法之美—Fire Net:www.cnblogs.com/lcw/p/3159414.html]类似 题目:在8 ...

  3. kali64位 安装 adb

    1,adb只有32位的  ,下载地址http://dl.dbank.com/c0umekbpxi# 2,下载解压,但是执行adb命令时,报./adb: error while loading shar ...

  4. webpack的代码分割/离

    两种方法: 1.webpack的methods----require.ensure 2.ES 2015的Loader spec //require.ensure语法 require.ensure [] ...

  5. Lintcode: Implement Queue by Stacks 解题报告

    Implement Queue by Stacks 原题链接 : http://lintcode.com/zh-cn/problem/implement-queue-by-stacks/# As th ...

  6. JS实现多行文本最后是省略号紧随其后还有个超链接在同一行的需求

    1.布局及样式如下图: 2.js获得上图的div对象,然后判断div对象的高度,如果大于一行的高度了表示内容有两行了,再获得span标签里面的内容并用正则将后六个字符替换成“......”这里的实现代 ...

  7. 分页用到的子查询sql语句

    说明(2017-8-31 23:30:22): 1. 分页用到的子查询sql语句 select * from(select *,ROW_NUMBER() over(order by id)as num ...

  8. 基于jQuery仿QQ音乐播放器网页版代码

    基于jQuery仿QQ音乐播放器网页版代码是一款黑色样式风格的网页QQ音乐播放器样式代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class="m ...

  9. jQuery弹性展开收缩菜单插件gooey.js

    分享一款基于jQuery弹性展开收缩菜单插件gooey.js.这是一款基于gooey.js插件实现的弹性菜单特效代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <hea ...

  10. [转]SpringMVC单文件上传、多文件上传、文件列表显示、文件下载

    一.新建一个Web工程,导入相关的包 springmvc的包+commons-fileupload.jar+connom-io.jar+commons-logging,jar+jstl.jar+sta ...