题解 | #走迷宫#

走迷宫

https://www.nowcoder.com/practice/e88b41dc6e764b2893bc4221777ffe64

题目链接

走迷宫

题目描述

在一个 的网格中,你从起点 出发,每次可以向上、下、左、右移动一步。某些格子是障碍物,无法通过。你需要计算从起点移动到终点 的最少步数。如果无法到达,则输出 -1。

解题思路

这是一个典型的在二维网格中寻找最短路径的问题。由于每次移动的成本(步数)都是 1,这是一个无权图的最短路径问题。解决此类问题的最佳算法是广度优先搜索 (Breadth-First Search, BFS)

BFS 的核心思想是从起点开始,逐层向外进行“地毯式”搜索。它首先访问所有距离起点为 1 的节点,然后是所有距离为 2 的节点,以此类推。由于这种逐层扩展的特性,当 BFS 第一次到达终点时,所经过的路径必然是步数最少的。

算法步骤如下:

  1. 数据结构

    • 一个队列,用于存储待访问的节点。队列中的每个元素需要包含节点的状态,即坐标 和到达该坐标的步数
    • 一个二维的距离数组 dist[N][M],用于记录从起点到每个格子的最短距离,并兼作访问标记。初始时,所有格子的距离都设为一个特殊值(如 -1),表示未访问。
  2. 初始化

    • 读取网格、起点和终点坐标。注意将题目中 1-based 的坐标转换为 0-based 的数组索引。
    • 将起点 (startX, startY) 的距离 dist[startX][startY] 设为 0。
    • 将起点的状态 (startX, startY, 0) 加入队列。
  3. BFS 循环

    • 当队列不为空时,取出队首元素 (x, y, steps)
    • 如果 (x, y) 是终点,那么 steps 就是最短步数,算法结束。
    • 否则,遍历当前格子的四个相邻方向(上、下、左、右),得到新的坐标 (nx, ny)
    • 对于每个新坐标,进行合法性检查:
      • 是否在网格范围内?
      • 是否为障碍物?
      • 是否已经访问过(即 dist[nx][ny] 不为 -1)?
    • 如果新坐标合法且未被访问,则更新其距离 dist[nx][ny] = steps + 1,并将其状态 (nx, ny, steps + 1) 加入队列。
  4. 处理无法到达的情况

    • 如果队列变空后,仍未到达终点,说明从起点无法到达终点。此时,终点的距离值 dist[endX][endY] 仍然是初始值 -1,我们应输出 -1。

代码

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <tuple>

using namespace std;

int main() {
    int n, m;
    cin >> n >> m;

    int sx, sy, ex, ey;
    cin >> sx >> sy >> ex >> ey;
    // 转换为 0-based 索引
    sx--; sy--; ex--; ey--;

    vector<string> grid(n);
    for (int i = 0; i < n; ++i) {
        cin >> grid[i];
    }

    vector<vector<int>> dist(n, vector<int>(m, -1));
    queue<tuple<int, int, int>> q;

    // 起点初始化
    dist[sx][sy] = 0;
    q.push({sx, sy, 0});

    // 定义四个方向
    int dx[] = {-1, 1, 0, 0};
    int dy[] = {0, 0, -1, 1};

    while (!q.empty()) {
        int x, y, d;
        tie(x, y, d) = q.front();
        q.pop();

        if (x == ex && y == ey) {
            cout << d << endl;
            return 0;
        }

        for (int i = 0; i < 4; ++i) {
            int nx = x + dx[i];
            int ny = y + dy[i];

            // 检查新坐标的合法性
            if (nx >= 0 && nx < n && ny >= 0 && ny < m &&
                grid[nx][ny] == '.' && dist[nx][ny] == -1) {
                
                dist[nx][ny] = d + 1;
                q.push({nx, ny, d + 1});
            }
        }
    }

    cout << -1 << endl;

    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();

        int sx = sc.nextInt() - 1;
        int sy = sc.nextInt() - 1;
        int ex = sc.nextInt() - 1;
        int ey = sc.nextInt() - 1;

        char[][] grid = new char[n][m];
        for (int i = 0; i < n; i++) {
            grid[i] = sc.next().toCharArray();
        }

        int[][] dist = new int[n][m];
        for (int[] row : dist) {
            Arrays.fill(row, -1);
        }

        Queue<int[]> q = new LinkedList<>();

        dist[sx][sy] = 0;
        q.offer(new int[]{sx, sy, 0});

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

        while (!q.isEmpty()) {
            int[] current = q.poll();
            int x = current[0];
            int y = current[1];
            int d = current[2];

            if (x == ex && y == ey) {
                System.out.println(d);
                return;
            }

            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];

                if (nx >= 0 && nx < n && ny >= 0 && ny < m &&
                    grid[nx][ny] == '.' && dist[nx][ny] == -1) {
                    
                    dist[nx][ny] = d + 1;
                    q.offer(new int[]{nx, ny, d + 1});
                }
            }
        }

        System.out.println(-1);
    }
}
import sys
from collections import deque

def main():
    # 读取输入
    n, m = map(int, sys.stdin.readline().split())
    sx, sy, ex, ey = map(int, sys.stdin.readline().split())
    # 转换为 0-based 索引
    sx, sy, ex, ey = sx - 1, sy - 1, ex - 1, ey - 1

    grid = [sys.stdin.readline().strip() for _ in range(n)]

    # 初始化距离/访问数组
    dist = [[-1] * m for _ in range(n)]
    
    # 初始化队列
    q = deque()
    
    dist[sx][sy] = 0
    q.append((sx, sy, 0))

    # 四个方向
    dx = [-1, 1, 0, 0]
    dy = [0, 0, -1, 1]

    while q:
        x, y, d = q.popleft()

        if x == ex and y == ey:
            print(d)
            return

        for i in range(4):
            nx, ny = x + dx[i], y + dy[i]

            if 0 <= nx < n and 0 <= ny < m and \
               grid[nx][ny] == '.' and dist[nx][ny] == -1:
                
                dist[nx][ny] = d + 1
                q.append((nx, ny, d + 1))

    print(-1)

if __name__ == "__main__":
    main()

算法及复杂度

  • 算法:广度优先搜索 (BFS)
  • 时间复杂度:每个格子最多被访问一次(入队和出队各一次),对每个格子我们会检查其四个邻居。因此,总时间复杂度为 ,其中 分别是网格的行数和列数。
  • 空间复杂度:空间主要由队列和 dist 数组占用。在最坏的情况下,队列可能需要存储接近所有格子的信息。dist 数组的大小是固定的。因此,总空间复杂度为
全部评论

相关推荐

点赞 评论 收藏
分享
嗨害嗨我来了:感谢我吧,上次我在食堂敲打了一个姓雷的,他说马上给大学生们准备hc
不卡学历的大厂有哪些?
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务