在 N×M 矩陣(N,M ≤ 200)迷宮中,包含牆壁(#)、道路(.)、天使(a)、朋友(r)、守衛(x)。移動上下左右耗時 1,殺死守衛額外耗時 1。求朋友到達天使的最短時間,不可達輸出 Poor ANGEL has to stay in the prison all his life.
標準 BFS 假設邊權為 1,但「遇守衛 +1」導致邊權為 1 或 2。解決方案:
time 字段,而非層次遍歷next.time < step[next.x][next.y] 才入隊(step 記錄到達該格最短時間)#include <cstdio>
#include <queue>
#include <cstring>
#define INF 0x3f3f3f3f
const int maxn = 200 + 10;
using namespace std;
int dx[4] = {0,0,-1,1}, dy[4] = {-1,1,0,0};
int step[maxn][maxn];
int n, m, sum;
char map[maxn][maxn];
struct Map { int x, y, time; };
queue<Map> q;
Map start, end;
int check(int x, int y) {
return x>=1 && x<=n && y>=1 && y<=m;
}
int bfs() {
Map current, next;
memset(step, 0x3f, sizeof(step));
step[start.x][start.y] = 0;
q.push(start);
int ans = INF;
while (!q.empty()) {
current = q.front(); q.pop();
if (current.time >= ans) continue; // 剪枝
for (int i = 0; i < 4; i++) {
next.x = current.x + dx[i];
next.y = current.y + dy[i];
next.time = current.time + 1;
if (map[next.x][next.y] == 'x') next.time++; // 遇守衛+1
if (check(next.x, next.y) && map[next.x][next.y] != '#'
&& next.time < step[next.x][next.y]) {
step[next.x][next.y] = next.time;
if (next.x == end.x && next.y == end.y) {
ans = min(ans, next.time);
} else {
q.push(next);
}
}
}
}
return ans == INF ? -1 : ans;
}
int main() {
while (scanf("%d%d", &n, &m) == 2) {
for (int i = 1; i <= n; i++) {
scanf("%s", map[i] + 1);
for (int j = 1; j <= m; j++) {
if (map[i][j] == 'a') end.x = i, end.y = j;
if (map[i][j] == 'r') start.x = i, start.y = j, start.time = 0;
}
}
int ans = bfs();
if (ans == -1)
puts("Poor ANGEL has to stay in the prison all his life.");
else
printf("%d\n", ans);
}
return 0;
}
傳統 BFS 用隊列大小控制層次,本題因邊權不一,改用節點攜帶 time,step[][] 記錄最短到達時間,實現類 Dijkstra 的 BFS 變體(因邊權僅 1/2,不需優先隊列)。
if (current.time >= ans) continue; // 已找到更優解
if (next.time < step[next.x][next.y]) { ... } // 只有更優才入隊
作者提到「0ms 通過」,得益於此剪枝。
while (scanf("%d%d", &n, &m) == 2) 讀到 EOF 結束,每輪重置全局狀態。
採用 1-based 索引,check() 邊界判斷簡潔:x>=1 && x<=n && y>=1 && y<=m。
Input:
7 8
#.#####.
#.a#..r.
#..#x...
..#..#.#
#...##..
.#......
........
Output:
13
x 可通行但 +1 時間,非障礙物r)?題目隱含單起點,代碼覆蓋 start 取最後一個%s 讀取跳過空白HDU 1242 是經典的「帶權障礙 BFS」入門題,核心在於將非均勻邊權轉化為節點時間狀態,配合 step[][] 剪枝實現高效求解。代碼簡潔、邏輯清晰,是 BFS 進階的優秀教學案例。