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  阅读(44)  评论(0)    收藏  举报