AcWing 844. 走迷宫

题目

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

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

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

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

输入格式

第一行包含两个整数 \(n\) 和 \(m\)。

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

输出格式

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

数据范围

\(1 \le n, m \le 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

题解

C++ 代码

#include <iostream>
#include <cstring>
#include <queue>  //利用stl库内的函数,无需自己用数组模拟队列
#include <algorithm>

using namespace std;

typedef pair<int, int> PII; //存储x,y坐标

const int N = 110;

int n, m;
int g[N][N], d[N][N]; //g[][]存储地图,d[][]存储移动距离(搜索深度)

int bfs()
{
    queue<PII> q; //先定义一个PII型队列,存储走过的点
    memset(d, -1, sizeof d); //将距离数组内所有点存储为-1,表示所有点都还没走过
    d[0][0] = 0; //表示坐标为(0, 0)的点已经走过,且移动距离为0
    q.push({0, 0}); //将(0, 0)放入队列

                                                      //定义方向向量一共四个方向,当在迷宫内任意一点,我们可以往上下左右四个方向上走,
                                                      //往上走是 行减一列不变 可以写成(-1,0) x表示行 y表示列
    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; // 所以往右走是行不变列加一 (0, 1)  往下走(1, 0) 往左走(0, -1) 我们分别将x和y 写在dx和dy内,一一对应

    while (q.size()) //队列不空时执行循环
    {
        auto t = q.front(); //取出队头元素, 表示当前位置,下面利用dx[] dy[] 移动位置使用

        q.pop(); //每次循环弹出一个位置保证循环可以正常终止
                //(例如当走到出口时,四个方向都走不通了,下面的if循环无法执行不会向队列内插入元素,但此时队列不空,while循环反复执行,不断从队列内弹出元素,最终队列为空,循环终止)

        for (int i = 0; i < 4; i ++ ) //枚举四个方向
        {
            int x = t.first + dx[i], y = t.second + dy[i]; //t.first取出队头里存储的一对数的第一个数(即是当前位置的x坐标)  同理t.second取出第二个数,即是当前位置y坐标
                                                           //当i=0时,dx[0] dy[0] 即(-1, 0) 向上移 当i++, 我们就可以在循环内将四个方向都走一遍,看是否满足下面if的条件
            if (x >= 0 && x < n && y >= 0 && y < m && g[x][y] == 0 && d[x][y] == -1) //当x和y均不越过迷宫的上下左右边界 且 走到了位置是0的点(g[x][y] == 0) 且 该路径没有被走过(d[x][y] == -1)
            {
                d[x][y] = d[t.first][t.second] + 1; //走到下一个点的同时距离加1
                q.push({x, y}); //将该点入队,进行下一次while循环
            }
        }
    }

    return d[n - 1][m - 1]; //返回走到右下角出口位置的移动距离 (坐标是(n - 1, m- 1))

}

int main()
{
    scanf("%d%d", &n, &m);

    //传入地图
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < m; j ++ )
            scanf("%d", &g[i][j]);

    printf("%d", bfs());
    return 0;
}
posted @ 2024-04-16 17:44  MsEEi  阅读(80)  评论(0)    收藏  举报