题解:AcWing 844 走迷宫

【题目来源】

AcWing:844. 走迷宫 - AcWing题库

【题目描述】

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

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

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

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

【输入】

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

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

【输出】

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

【输入样例】

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

【解题思路】

image

【代码详解】

《AcWing 844 走迷宫》 #BFS#

// 使用STL队列
#include <bits/stdc++.h>
using namespace std;

const int N = 110;  // 定义地图最大尺寸

// 定义节点结构体,存储位置和步数
struct Node 
{
    int x;     // 当前节点的x坐标
    int y;     // 当前节点的y坐标
    int step;  // 从起点到当前节点的步数
};

int n, m;        // 地图的行数和列数
int g[N][N];     // 存储地图信息(0表示可通行,1表示障碍)
bool vis[N][N];  // 标记数组,记录节点是否被访问过
int dx[4] = {-1, 0, 1, 0};  // 四个方向的x偏移量(上、右、下、左)
int dy[4] = {0, 1, 0, -1};   // 四个方向的y偏移量(上、右、下、左)
queue<Node> q;   // BFS使用的队列

// 检查坐标(x,y)是否合法且可通行
bool check(int x, int y)
{
    // 检查是否越界
    if (x < 1 || x > n || y < 1 || y > m) 
        return false;
    // 检查是否是障碍物
    if (g[x][y] == 1) 
        return false;
    // 检查是否已被访问
    if (vis[x][y]) 
        return false;
    return true;
}

// BFS算法实现,返回从起点到终点的最短步数
int bfs(int x, int y, int step)
{
    // 标记起点为已访问
    vis[x][y] = true;
    // 将起点加入队列
    q.push(Node{x, y, step});
  
    // 当队列不为空时循环
    while (!q.empty()) 
    {
        // 取出队首节点
        Node nownode = q.front(); 
        q.pop();
      
        // 如果到达终点,返回当前步数
        if (nownode.x == n && nownode.y == m) 
        {
            return nownode.step;
        }
      
        // 遍历四个方向
        for (int i = 0; i < 4; i++) 
        {
            int nx = nownode.x + dx[i];  // 计算新位置的x坐标
            int ny = nownode.y + dy[i];  // 计算新位置的y坐标
          
            // 如果新位置合法且未被访问
            if (check(nx, ny)) 
            {
                vis[nx][ny] = true;  // 标记为已访问
                // 将新节点加入队列,步数+1
                q.push(Node{nx, ny, nownode.step + 1});
            }
        }
    }
    // 如果无法到达终点,返回-1
    return -1;
}

int main()
{
    // 输入地图尺寸
    cin >> n >> m;
  
    // 输入地图数据
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> g[i][j];
  
    // 调用BFS并输出结果
    cout << bfs(1, 1, 0) << endl;
  
    return 0;
}
// 数组模拟队列(优先推荐)
#include <bits/stdc++.h>
using namespace std;

const int N = 110;          // 定义地图最大尺寸
typedef pair<int, int> PII; // 定义坐标对类型

int n, m;                   // 地图的行数和列数
int g[N][N];                // 存储地图信息(0表示可通行,1表示障碍)
int d[N][N];                // 存储每个位置到起点的最短距离
PII q[N * N];               // 数组模拟的队列,存储待处理的坐标

// BFS算法实现,返回从起点到终点的最短步数
int bfs()
{
    int hh = 0, tt = 0;     // 队列头指针和尾指针
    q[0] = {0, 0};          // 将起点(0,0)加入队列
    memset(d, -1, sizeof(d)); // 初始化距离数组为-1(表示未访问)
    d[0][0] = 0;            // 起点到自己的距离为0
  
    // 定义四个方向的偏移量(上、右、下、左)
    int dx[4] = {-1, 0, 1, 0};
    int dy[4] = {0, 1, 0, -1};
  
    // 当队列不为空时循环
    while (hh <= tt)
    {
        auto t = q[hh++];   // 取出队首元素
      
        // 遍历四个方向
        for (int i = 0; i < 4; i++)
        {
            int x = t.first + dx[i];  // 计算新位置的x坐标
            int y = t.second + dy[i]; // 计算新位置的y坐标
          
            // 检查新位置是否合法且未被访问
            if (x >= 0 && x < n && y >= 0 && y < m && g[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 >> g[i][j];
  
    // 调用BFS并输出结果
    cout << bfs() << endl;
  
    return 0;
}

【运行结果】

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
posted @ 2026-02-21 20:06  团爸讲算法  阅读(6)  评论(0)    收藏  举报