广度优先搜索(BFS)之走迷宫

题目描述

给定一个N×M 的网格迷宫G。G 的每个格子要么是道路,要么是障碍物(道路用 1 表示,障碍物用 0 表示)。

已知迷宫的入口位置为(x1​,y1​),出口位置为(x2​,y2​)。问从入口走到出口,最少要走多少个格子。

输入描述

输入第 1 行包含两个正整数N,M,分别表示迷宫的大小。

接下来输入一个N×M 的矩阵。若 Gi,j​=1 表示其为道路,否则表示其为障碍物。

最后一行输入四个整数x1​,y1​,x2​,y2​,表示入口的位置和出口的位置。

1≤N,M≤10^{2},0≤Gi,j​≤1,1≤x1​,x2​≤N,1≤y1​,y2​≤M。

输出描述

输出仅一行,包含一个整数表示答案。

若无法从入口到出口,则输出−1。

输入输出样例

示例 1

输入

5 5 
1 0 1 1 0
1 1 0 1 1 
0 1 0 1 1
1 1 1 1 1
1 0 0 0 1
1 1 5 5 

输出

8

运行限制

语言最大运行时间最大运行内存
C++1s128M
C1s128M
Python31s128M
Java1s128M

思路 

读题可知要求寻找两点的最短路径,可以用宽搜的办法。首先输入了一系列数值,将矩阵保存在二维数组,注意题目给的坐标是正常类型(可转成从0开始的坐标,即输入后减1),随后进行宽搜。简单来说,宽搜是从一点出发,向四周扩散寻找路,期间可能遇见越界、障碍物等,并且在扩散的过程中记录新点距离起点的距离,直到找到终点。bfs的具体思路为:

1. 首先,我们创建一个队列 q (先进先出)来存储待访问的位置。初始时,我们将起点(x1​,y1​)加入队列。

2. 然后我们进入一个循环,当队列非空时,执行一下操作:

        2.1 从队列的头部取出一个位置 t ,这就是我们当前要处理的位置。(t.x​, t.y)

        2.2 然后我们尝试向四个方向移动(顺时针),对于每个方向,计算出新的位置(tx, ty)。

        2.3 接下来,我们需要检查新的位置是否在网格内(越界),以及是否可以走(障碍)。如果新的位置在网格内,并且可以走,那么继续处理这个位置。

        2.4 将新的位置(tx, ty)标记为 0,表示这个位置已经被访问过,不需要再访问了。然后,我们计算到这个位置的距离,它等于从起点到当前位置的距离加一。

        2.5 如果新的位置就是终点 (x1, y2),那么就找到了一条路径,可以直接返回这个距离,这是由于BFS是按照距离递增的顺序来访问位置的,所以当我们第一次访问到终点时,找到的就是最短路径。

        2.6 最后我们将新的位置(tx, ty)加入队列,等待后续处理。

3. 当队列为空时,如果我们还没有找到路径,那就表示从起点到终点没有联通路径,返回-1。

代码一

#include <iostream>
#include <queue>

using namespace std;
//定义集合键值对
#define x first
#define y second

const int N = 1e3 + 10;
typedef pair<int, int> PII;
int n, m, A, B, C, D;
char g[N][N];
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int count = 0;

int bfs(){
  queue<PII> q;  //初始化坐标型队列
  q.push({A, B});  //将起点放入队列

  while(!q.empty()){  //当队列不为空,进入循环
    auto t = q.front();  //获取当前位置
    q.pop();  //将其从队列移出

    for(int i = 0; i < 4; i++){
      int tx = t.x + dx[i], ty = t.y + dy[i];  //获取新的位置
      if(tx < 0 || ty < 0 || tx >=n || ty >=m || g[tx][ty]=='0')  //越界、障碍
        continue;
      g[tx][ty] = '0'; //可访问设为已访问
      count++;
      if(tx == C && ty == D)
        return count;
      q.push({tx, ty}); //没到终点,将新的位置放入队列,等待下一次调用
    }
  }
  return -1; //无路径
}

int main(){
  cin >> n >> m;
  for(int i = 0; i < n; i++)
    for(int j = 0; j < m; j++)
      cin >>g[i][j];

  cin >> A >> B >> C >> D;
  //从0开始计算坐标
  A--;
  B--;
  C--;
  D--;
  cout << bfs();
  return 0;
}

代码执行结果

上述代码一是有错误的,即利用了count++的方式来计算路径,但这只适用于每一次四个方向的寻找都只有一条路的问题,反之则将其余可走路径也进行了count++。 

代码二

#include <iostream>
#include <queue>

using namespace std;
//定义集合键值对
#define x first
#define y second

const int N = 1e3 + 10;
typedef pair<int, int> PII;
int n, m, A, B, C, D;
char g[N][N];
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int dist[N][N];

int bfs(){
  queue<PII> q;  //初始化坐标型队列
  q.push({A, B});  //将起点放入队列

  while(!q.empty()){  //当队列不为空,进入循环
    auto t = q.front();  //获取当前位置
    q.pop();  //将其从队列移出

    for(int i = 0; i < 4; i++){
      int tx = t.x + dx[i], ty = t.y + dy[i];  //获取新的位置
      if(tx < 0 || ty < 0 || tx >=n || ty >=m || g[tx][ty]=='0')  //越界、障碍
        continue;
      g[tx][ty] = '0'; //可访问设为已访问
      dist[tx][ty] = dist[t.x][t.y] + 1; //距离加1(初始为0)
      if(tx == C && ty == D)
        return dist[tx][ty];
      q.push({tx, ty}); //没到终点,将新的位置放入队列,等待下一次调用
    }
  }
  return -1; //无路径
}

int main(){
  cin >> n >> m;
  for(int i = 0; i < n; i++)
    for(int j = 0; j < m; j++)
      cin >>g[i][j];

  cin >> A >> B >> C >> D;
  //从0开始计算坐标
  A--;
  B--;
  C--;
  D--;
  cout << bfs();
  return 0;
}

代码执行结果

 

上述代码二初始化一个数组来存放每一个坐标距离起点的距离,保证每个坐标的距离是独立的。

总结

宽搜的前置知识是坐标系和队列,前者用来存储矩阵数据,后者用来对数据进行先进先出的操作。

  • 23
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是用广优先算法生成走迷宫Python 代码: ```python from queue import Queue # 迷宫地图,其中 0 表示可走的路,1 表示障碍物 maze = [ [0, 0, 0, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [1, 0, 0, 1, 0], [0, 0, 0, 0, 0] ] # 迷宫的行数和列数 n = len(maze) m = len(maze[0]) # 起点和终点坐标 start_pos = (0, 0) end_pos = (n-1, m-1) # 定义四个方向的偏移量 directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] # 广优先算法 def bfs(): # 初始化队列和起点 q = Queue() q.put(start_pos) visited = set() visited.add(start_pos) # 开始索 while not q.empty(): cur_pos = q.get() # 判断是否到达终点 if cur_pos == end_pos: return True # 索当前位置的四个方向 for d in directions: next_pos = (cur_pos[0]+d[0], cur_pos[1]+d[1]) # 判断下一个位置是否越界或者是障碍物 if next_pos[0] < 0 or next_pos[0] >= n or next_pos[1] < 0 or next_pos[1] >= m or maze[next_pos[0]][next_pos[1]] == 1: continue # 判断下一个位置是否已经访问过 if next_pos not in visited: q.put(next_pos) visited.add(next_pos) # 没有找到终点 return False # 调用广度优先搜索函数 if bfs(): print("可以到达终点!") else: print("无法到达终点!") ``` 这段代码中,我们使用队列来实现广度优先搜索,每次从队列中取出一个位置,然后索它周围的四个方向,如果下一个位置没有越界、不是障碍物,并且没有访问过,就将它加入队列中。如果索到了终点,就返回 True,否则返回 False。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值