迷宫最短路径
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;
}

浙公网安备 33010602011771号