給定 N×M 網格,每個格子有一個方向(0-7 對應 8 鄰域)。船隻順流(按格子指示方向移動)無時間成本,逆流(移動到其他 7 個方向)耗時 1。求從起點到終點的最小時間。多組查詢,網格不變。
邊權只有 0 和 1,經典 Dijkstra 可用優先隊列,但 **0-1 BFS 用雙端隊列 O(V+E) 更快**。
#include
using namespace std;
const int MAXN = 1005;
const int dx[8] = {-1,-1,0,1,1,1,0,-1};
const int dy[8] = {0,1,1,1,0,-1,-1,-1};
int n, m;
char grid[MAXN][MAXN];
int dist[MAXN][MAXN];
struct Node { int x, y; };
bool inside(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m;
}
int bfs(int sx, int sy, int ex, int ey) {
if (sx == ex && sy == ey) return 0;
memset(dist, 0x3f, sizeof(dist));
deque dq;
dist[sx][sy] = 0;
dq.push_front({sx, sy});
while (!dq.empty()) {
Node cur = dq.front(); dq.pop_front();
int d = dist[cur.x][cur.y];
if (cur.x == ex && cur.y == ey) return d;
int dir = grid[cur.x][cur.y] - '0'; // 當前格子指示方向
// 1. 順流方向 (權重 0)
int nx = cur.x + dx[dir];
int ny = cur.y + dy[dir];
if (inside(nx, ny) && dist[nx][ny] > d) {
dist[nx][ny] = d;
dq.push_front({nx, ny});
}
// 2. 其他 7 個方向 (權重 1)
for (int i = 0; i < 8; i++) {
if (i == dir) continue;
nx = cur.x + dx[i];
ny = cur.y + dy[i];
if (inside(nx, ny) && dist[nx][ny] > d + 1) {
dist[nx][ny] = d + 1;
dq.push_back({nx, ny});
}
}
}
return -1; // 不可達 (題目保證可達)
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
while (cin >> n >> m) {
for (int i = 0; i < n; i++) cin >> grid[i];
int T; cin >> T;
while (T--) {
int sx, sy, ex, ey;
cin >> sx >> sy >> ex >> ey;
// 輸入 1-based 轉 0-based
cout << bfs(sx-1, sy-1, ex-1, ey-1) << '\n';
}
}
return 0;
}
0-1 BFS 是處理邊權為 {0,1} 圖的最短路徑「殺手鐧」。本題通過雙端隊列將優先隊列優化掉,體現了「選對數據結構,複雜度降維打擊」的算法美感。