广度优先搜索--什么是“BFS”?为什么要用队列实现?--走迷宫代码详细注释

什么是“DFS”

DFS 全称是 Depth First Search,中文名是深度优先搜索,是一种用于遍历或搜索树或图的算法。
在这里插入图片描述
深度优先,就是每次都尝试向更深的节点走。

什么是“BFS”

BFS全称是 Breadth First Search,中文名是宽度优先搜索,也叫广度优先搜索
其中的广度优先,就是每次都尝试访问同一层的节点, 如果同一层都访问完了,再访问下一层。
在这里插入图片描述
这样做的结果是,BFS 算法找到的路径是从起点开始的最短合法路径。换言之,这条路径所包含的边数最小。也就是说通过BFS算法只要找到目标节点,该路径就是最短路径。

为什么要用队列?

队列的原理是先进先出,而广度优先搜索类似于树的层次遍历,从离根节点最近的点开始向外扩散,因此用队列将最先遍历的点存入,后遍历的点后存入,符合bfs的逻辑。

首先我们先看BFS的节点处理顺序:
第一轮:处理根节点(第一层节点)
第二轮:处理根节点的所有子节点(第二层节点)
第三轮:处理距离根节点两步的所有节点(第三层节点)

然后我们对比队列的入队和出队顺序:
首先将根节点入队
第一轮:将根节点出队,对根节点进行处理,然后将所有的邻居(根节点的所有子节点)入队。但是新添加的节点不会立即遍历,而是在下一轮中处理。
结点的处理顺序与它们添加到队列的顺序是完全相同的顺序,即先进先出(FIFO)。这就是我们在 BFS 中使用队列的原因。

举例(走迷宫):

在这里插入图片描述

主要思想就是需要定义一个队列,和一个标记数组,标记数组主要用来记录步数,并且判断是否走过(该节点是否已经处理过)。
首先将入口坐标入队,并且将入口坐标在标记数组的值改为0(表示当前0步)
其次进入循环,将入口坐标进行出队,然后上下左右遍历,当相邻节点符合条件时将该节点入队,并且更新该节点在标记数组的值+1(表明当前距离起点有1步)。再进行判断该节点是否等于出口。如果等于直接返回当前步数。
然后再进行循环,对相邻节点。因为队列的特性,优先处理的都是相邻节点。
因此当找到出口位置时,就是最优路径。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;
// 定义地图
int ditu[110][110];
// 标记节点,没走过的初始化为-1,走过的标记为1
int label[110][110];
// 定义地图大小,N行M列 
int N, M;
// 定义坐标入口x_r,y_r,出口x_c,y_c
int x_r, y_r, x_c, y_c;
// 定义队列
queue<PII> q;

// 广度优先搜索
int bfs()
{
  // 初始化标记数组
  memset(label, -1, sizeof(label));
  label[x_r][y_r] = 0;
  // 将即将搜索的节点压入队列
  q.push({x_r, y_r});
  // 定义上下左右
  int x_move[4] = {-1, 0, 1, 0}, y_move[4] = {0, 1, 0, -1};
  // 当队列不为空时则路径没有全部遍历结束,为空说明地图全部走完
  while(q.size())
  {
    // 将节点取出
    auto head = q.front();
    q.pop();
    // 将该节点进行移动
    for(int i=0; i<4; i++)
    {
      // 更新移动后的位置
      int x = head.first + x_move[i];
      int y = head.second + y_move[i];
      // 对更新后的位置进行判断
      // 满足在边界内,该位置没有障碍物,该位置没有走过(没有被标记过)
      if(x>=1 && x <= N && y>=1 && y<=M && ditu[x][y]==1 && label[x][y]==-1)
      {
        // 记录步数,当前节点与入口的距离
        label[x][y] = label[head.first][head.second] + 1;
        // 给当前节点入队,在下次循环时以该节点为起始进行上下左右
        q.push({x,y});
        // 判断当前位置是否是出口,如果是则返回步数
        if(x==x_c && y==y_c)
        {
          return label[x][y];
        }
      }
    }
  }
  // 如果所有节点都遍历结束都没有出口,则返回-1
  return -1;
}
int main()
{
  // 输入地图大小
  cin >> N >> M;
  for(int i=1; i<=N; i++)
  {
    for(int j=1; j<=M; j++)
    {
      cin >> ditu[i][j];
    }
  }
  cin >> x_r >> y_r >> x_c >> y_c;
  cout << bfs();
  return 0;
}
  • 14
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值