迷宫最短路径

2025.9.11

题目内容

给定一个迷官的地图,地图是一个二维矩阵,其中 \(0\) 表示通道, \(1\) 表示墙壁, \(S\) 表示起点, \(E\) 表示终点。你需要从起点 \(S\) 出发,通过最短路径到达终点 \(E\) ,返回最短路径的步数,如果无法到达终点,则返回 \(-1\) ,迷宫中会有虫洞,用数字 \(2\) 表示,成对出现,你走入虫洞可以穿越到另一个虫洞出口,耗费 \(0\)

你只能上下左右移动,并且不能走出迷官的边界,也不能穿越墙壁

输入描述

第一行包含两个整数 \(m,n\)\(1 \le m,n \le 50\)),表示迷宫的行数和列数

接下来的\(m\)行,每行包含\(n\)个字符,表示迷宫的地图。字符为:

\(0\):表示通道

\(1\):表示墙壁

\(2\):表示虫洞

\(S\):表示起点

\(E\):表示终点

输出描述

如果能够到达终点,输出最短路径的步数
如果无法到达终点,输出\(-1\)

输入输出样例

输入

3 3
S02
111
E02

输出

4

C++实现

#include <bits/stdc++.h>
using namespace std;
using pii = pair<int,int>;
const int INF = 1e9;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int m, n;
    if (!(cin >> m >> n)) return 0;

    vector<string> maze(m);
    for (int i = 0; i < m; ++i) {
        cin >> maze[i];
        // 若用户输入中可能有空格或分段,这里尽量保证每行长度为 n
        while ((int)maze[i].size() < n) {
            string more;
            if (!(cin >> more)) break;
            maze[i] += more;
        }
    }

    pii start(-1,-1), endp(-1,-1);
    vector<pii> wormholes;
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            if (maze[i][j] == 'S') start = {i, j};
            else if (maze[i][j] == 'E') endp = {i, j};
            else if (maze[i][j] == '2') wormholes.emplace_back(i, j);
        }
    }

    // 将虫洞按出现顺序两两配对(支持多对)
    unordered_map<int, pii> wormMap; // key = x * n + y
    for (size_t i = 0; i + 1 < wormholes.size(); i += 2) {
        pii a = wormholes[i], b = wormholes[i+1];
        wormMap[a.first * n + a.second] = b;
        wormMap[b.first * n + b.second] = a;
    }
    // 若虫洞数量为奇数,最后一个不配对(不会传送)

    if (start.first == -1 || endp.first == -1) {
        cout << -1 << '\n';
        return 0;
    }

    // 0-1 BFS
    deque<pii> dq;
    vector<vector<int>> dist(m, vector<int>(n, INF));
    dist[start.first][start.second] = 0;
    dq.emplace_front(start);

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

    while (!dq.empty()) {
        auto cur = dq.front(); dq.pop_front();
        int x = cur.first, y = cur.second;
        int d = dist[x][y];

        if (x == endp.first && y == endp.second) break; // 最短已确定

        // 虫洞传送:代价 0,加入队头
        if (maze[x][y] == '2') {
            int key = x * n + y;
            auto it = wormMap.find(key);
            if (it != wormMap.end()) {
                pii dest = it->second;
                int wx = dest.first, wy = dest.second;
                if (dist[wx][wy] > d) {
                    dist[wx][wy] = d;
                    dq.emplace_front(dest);
                }
            }
        }

        // 四个方向:代价 1,加入队尾
        for (int k = 0; k < 4; ++k) {
            int nx = x + dx[k], ny = y + dy[k];
            if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;
            if (maze[nx][ny] == '1') continue; // 墙
            if (dist[nx][ny] > d + 1) {
                dist[nx][ny] = d + 1;
                dq.emplace_back(nx, ny);
            }
        }
    }

    if (dist[endp.first][endp.second] == INF) cout << -1 << '\n';
    else cout << dist[endp.first][endp.second] << '\n';

    return 0;
}

posted @ 2025-09-11 22:05  安度因小王子  阅读(36)  评论(0)    收藏  举报