BFS简单迷宫问题

给定一个n*m的二维整数数组,用来表示一个迷宫,数组中只包含0或1,其中0表示可以走的路,1表示不可通过的墙壁。

最初,有一个人位于左上角(1, 1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。

请问,该人从左上角移动至右下角(n, m)处,至少需要移动多少次。

数据保证(1, 1)处和(n, m)处的数字为0,且一定至少存在一条通路。

输入格式
第一行包含两个整数n和m。

接下来n行,每行包含m个整数(0或1),表示完整的二维数组迷宫。

输出格式
输出一个整数,表示从左上角移动至右下角的最少移动次数。

数据范围
1≤n,m≤100

样例
输入样例:
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出样例:
8

我们的思路是用模拟队列来写hh表示当前的点
tt表示下一步可以走的点,相当于将一个二维转化为一维的,(其实也就是遍历次序的问题比如说(0.0)-(0.1)-(0.2)-(1.2)这个顺序可以是二维空间移动来看,也可以是给每一个点一个数字来代表它的次序1-2-3-4)

然后用一个数组d来表示没有走过的地方,和存每一可以走的点到初始点的距离。
通过四个偏移量上下左右,和for循环遍历每一次可以走的路径最终到终点输出答案。

代码如下:

#include<iostream>
#include<cstring>

using namespace std;

const int N = 1e2 + 10;

typedef pair<int ,int> PII;

int d[N][N], map[N][N],n,m;
PII q[N*N];


int bfs()
{
  int hh = 0, tt = 0;
  q[0] = {0,0};
  
  memset (d,-1,sizeof(d));
  d[0][0] = 0;
  
  int dx[4] = {-1,0,1,0},dy[4]{0,1,0,-1};
  
  while(hh <= tt)//tt代表可以进行下一步的点x
  {
      auto t = q[hh ++];
      for(int i = 0;i < 4;i++)
      {
        int x = t.first + dx[i],y = t.second + dy[i];
        if(x >= 0 && x < n && y >= 0 && y < m &&  map[x][y] == 0 && d[x][y] == -1)
        {
            d[x][y] = d[t.first][t.second] + 1;
            q[++ tt] = {x,y};
        }
      }
  }
  return d[n-1][m-1];
}
int main()
{
    cin >> n >> m;
    
    for(int i = 0;i < n;i ++)
        for(int j = 0;j < m;j++)
         cin >> map[i][j];
         
    cout << bfs() << endl;
    
    return 0;
}

代码分析:
代码核心是bfs那一块

int bfs()
{
  int hh = 0, tt = 0;
  q[0] = {0,0};
  
  memset (d,-1,sizeof(d));
  d[0][0] = 0;
  
  int dx[4] = {-1,0,1,0},dy[4]{0,1,0,-1};
  
  while(hh <= tt)//tt代表可以进行下一步的点x
  {
      auto t = q[hh ++];
      for(int i = 0;i < 4;i++)
      {
        int x = t.first + dx[i],y = t.second + dy[i];
        if(x >= 0 && x < n && y >= 0 && y < m &&  map[x][y] == 0 && d[x][y] == -1)
        {
            d[x][y] = d[t.first][t.second] + 1;
            q[++ tt] = {x,y};
        }
      }
  }
  return d[n-1][m-1];
}

首先初始化
hh代表当前的点,队列头
tt代表下一步可以走的点,队列尾
q存的是每个点的坐标。
d存的是每个点到原点的距离,以及用-1表示这个点没有被走过。


分析代码

int dx[4] = {-1,0,1,0},dy[4]{0,1,0,-1};

是偏移量,配合for循环使用。

while(hh <= tt)//tt代表可以进行下一步的点x
  {
      auto t = q[hh ++];
      for(int i = 0;i < 4;i++)
      {
        int x = t.first + dx[i],y = t.second + dy[i];
        if(x >= 0 && x < n && y >= 0 && y < m &&  map[x][y] == 0 && d[x][y] == -1)
        {
            d[x][y] = d[t.first][t.second] + 1;
            q[++ tt] = {x,y};
        }
      }
  }
  return d[n-1][m-1];
}

hh 表示队列头,tt表示队列尾
当 hh <= tt时表示队列里面还有数字没有遍历完.
进入while循环,
首先取出队列里面的头个数字
auto t = q[hh++]取玩后并让hh向后移动一位,auto 是会智能定义类型实际是 pair<int ,int>,因为我们用了

typedef pair<int ,int> PII;

所以也可以是PII .
在进入for循环,遍历四个偏移量,就是让它移动一下,用另一个变量来存储这个变化后的值。

int x = t.first + dx[i],y = t.second + dy[i];

每有一个移动成功,就是满足if语句里面的所有要求时,

if(x >= 0 && x < n && y >= 0 && y < m &&  map[x][y] == 0 && d[x][y] == -1)

第一个x>=0不能出左边界,x<n(数组从0开始记录所以没有等于号)不能出右边界 y>=0不能出上边界,y< m(数组从0开始记录的所以没有等于号)不能出下边界。map[][]=0是可以走的格子,d[x][y]=-1是没有被走过的格子。
满足要求时,

d[x][y] = d[t.first][t.second] + 1;
            q[++ tt] = {x,y};

记录这个走到的格子的距离=前一个格子所代表的距离 + 1
再把这个格子坐标加到对列里面.

在进行这个hh的下一个偏移量,重复以上操作。然后因为我们是拿新的变量存那个偏移量,所以每一次进for循环都是初始值。
然后以此类推,就得出答案了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值