设为首页 加入收藏

TOP

啊哈算法之宽搜BFS解救小哈(一)
2019-09-03 02:59:16 】 浏览:36
Tags:算法 BFS 解救

简述

本算法摘选自啊哈磊所著的《啊哈!算法》第四章第三节的题目——BFS算法再次解救小哈。文中代码使用C语言编写,博主通过阅读和理解,重新由Java代码实现了一遍,以此来理解BFS算法。关于解救小哈的迷宫题目,可以参看前一篇博文。

啊哈算法之解救小哈:https://www.cnblogs.com/captainad/p/11039967.html

解法思路

本篇博文,我们将利用广度优先搜索(Breadth First Search, BFS)(也称宽度优先搜索)算法来解决这个问题。

假设有如下迷宫地图:

最开始,我们从(1, 1)的位置开始,一步之内能够到达的点有(1, 2)和(2, 1)。

但是小哈并不在这两个点上,那我们只能通过(1,  2)和(2, 1)这两个点继续往下走。比如我们现在走到了(1, 2)这个点,之后又有可能到那个新的点呢?只有(2, 2)了,因为(1, 3)这个点是墙,无法通行的。那再看看通过(2, 1)这个点再走一步能够到达哪些点?可以到达(2, 2)和(3, 1)。此时会发现(2, 2)这个点既可以从(1, 2)到达也可以从(2, 1)到达,并且都只使用了2步。为了防止一个点多次被走到,我们使用桶(book数组)来记录是否被走到过。

此时我们可以走到的点就全部走到了,有(2, 2)和(3, 1),但是小哈并不在这两个点上,那我们得继续尝试往下找,看看通过(2, 2)和(3, 1)这两个点还能到达哪些新的没有走过的点。通过(2, 2)这个点我们可以到达(2, 3)和(3, 2),通过(3, 1)这个点我们可以到达(3, 2)和(4, 1)。现在3步可以到达的点有(2, 3)、(3, 2)和(4, 1),依旧没有到达目标位置即小哈所在的点,那么我们需要重复刚才的方法,直到到达小哈所在的点为止。

总结上面的算法,我们可以用一个队列来模拟这个过程

我们从一个点开始,并先将这个点入队,开始扩展时,分别往上下左右四个方向走一步,如果这一步没有被走过且没有遇到墙,则将这一步的点位入队,继续扩展,当对上一个点位扩展完了之后,这个点位对于当前来说已经没有用了,就将这个点位出队,接下来,在刚刚那个点位扩展出来的这几个点位的基础上按照上面的方式继续向下探索,这样一来,我们可以记录下从起点开始每走一步就能到达的点位,如果没有到达目标点位,则需要继续探索,否则停止。

我们从上面的图示结合队列来进心一番运算,来明白使用队列解决此问题的奥秘。

首先我们从(1, 1)这个点开始,将这个点入队,然后开始往上下左右四个方向(可使用数组来表示方向)进行探索,发现可以向右到达(1, 2)以及向下到达(2, 1),并且每扩展到一个可行的点位就入队列,向左和向上就出界了,于是从(1, 1)这个点走一步能够扩张到的点已经全部找齐,此时队列中就有(1, 1)、(1, 2)和(2, 1),对(1, 1)这个点位扩展完毕之后,这个点就没有存在的意义了,所以将此点出队,于是队首就是(1, 2),接着我们开始从(1, 2)这个点开始向四个方向探索,重复上面的步骤即可,直到找到目标为位置为止。(可以结合画图来理解这个步骤和意图)

从上面的分析我们可以得出,从某个点开始探索,每次往四个方向探索,且只走一步,遇到可行的点位就入队列,探索完一番之后,将队首的那个点位出队,因为这个点位就探索完了,接着往下一个点位探索,即新队首的点位,如此往复层层递进,直到探索到目标位置。

代码实现

  1 /**
  2  * @Project: dailypro
  3  * @PackageName: com.captainad.algorithm
  4  * @Author: Captain&D
  5  * @Websit: https://www.cnblogs.com/captainad/
  6  * @DateTime: 2019/6/19 15:31.
  7  * @Description: 使用广度优先搜索算法解救小哈
  8  */
  9 public class SaveBfs {
 10 
 11     /**
 12      * 自定义节点,表示地图上的某个点位及其相关信息
 13      */
 14     static class BfsNode {
 15 
 16         /** 横坐标 */
 17         int x;
 18 
 19         /** 纵坐标 */
 20         int y;
 21 
 22         /** 父节点在队列中的编号,输出路径时使用 */
 23         int f;
 24 
 25         /** 步数 */
 26         int s;
 27     }
 28 
 29     /**
 30      * 自定义队列,用来记录探索点位的步骤
 31      */
 32     static class BfsQueue {
 33         BfsNode[] data = new BfsNode[2500];
 34         int head;
 35         int tail;
 36         public BfsQueue(int head, int tail) {
 37             this.head = head;
 38             this.tail = tail;
 39         }
 40     }
 41 
 42     public static void main(String[] args) {
 43 
 44         // 定义一个表示走方向的数组,分别时向右、向下、向左、向上
 45         int[][] next = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
 46 
 47         // 定义一个桶,用来标记已经路过的点
 48         int[][] book = new int[50][50];
 49 
 50         // 初始化地图矩形大小,初始化地图数据,略
 51         int m = 5, n = 4;
 52         int[][] map = new int[50][50];
 53 
 54         // 测试用数据
 55         map[0][0] = 0;
 56         map[0][1] = 0;
 57         map[0][2] = 1;
 58         map[0][3] = 0;
 59         map[1][0] = 0;
 60         map[1][1] = 0;
 61         map[1][2] = 0;
 62         map[1][3] = 0;
 63         map[2][0] = 0;
 64         map[2][1] = 0;
 65         map[2][2] = 1;
 66         map[2][3] = 0;
 67         map[3][0] = 0;
 68         map[3][1] = 1;
 69         map[3][2] = 0;
 70         map[3][3] = 0;
 71         map[4][0] = 0;
 72         map[4][1] = 0;
 73         map[4][2] = 0;
 74         map[4][3] = 1;
 75 
 76         // 初始化入口坐标
 77         int startx = 0, starty = 0;
 78 
 79         // 目标点位
 80         int q = 3, p = 2;
 81 
 82         // 队列初始化
 83         BfsQueue queue = new BfsQueue(0, 0);
 84 
 85         // 往队列插入迷宫的入口坐标,同时在桶中标记
 86         BfsNode startNode = new BfsNode();
 87         startNode.x = startx;
 88         startNode.y = starty;
 89         startNode.f = 0;
 90         startNode.s = 0;
 91         queue.data[queue.tail] = startNode;
 92         queue.tail++;
 93 
 94         // 用于标记是否达到目的点位,1表示到达
 95         int flag = 0;
 96 
 97         //
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇[Java] 缓存池 下一篇java源码

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目