題目描述:給定一個 n×n 的棋盤,棋盤上有蛇和梯子。從格子 1 開始,每次可以擲骰子(1 到 6 點),移動到對應格子;若該格子有蛇或梯子,則必須移動到其目的地。求從格子 1 到格子 n² 所需的最少骰子次數;若無法到達則回傳 -1。
解題思路:本題是求「最少步數」的最短路徑問題,直觀上適合使用 BFS(廣度優先搜尋)。
最關鍵的挑戰在於座標轉換:棋盤採用蛇形(Boustrophedon)排列——第 1 行從左到右,第 2 行從右到左,依此交替。給定格子編號 num(1-indexed),需轉換為棋盤的 (row, col) 座標:
num - 1 轉為 0-indexed 的 posrow_from_bottom = pos / n(從底部算起的行號)col = pos % n;若該行是奇數行(從底部),則 col = n - 1 - col(反向)r = n - 1 - row_from_bottomBFS 中,每個狀態是當前格子編號,每次嘗試擲骰 1 到 6,計算新格子編號,若有蛇/梯子則跳轉,若未訪問則加入佇列。BFS 保證第一次到達終點時的步數即為最少步數。
時間複雜度:O(n²) — 棋盤共有 n² 個格子,每個格子最多被 BFS 訪問一次;每次訪問最多嘗試 6 個骰子值,為常數。
空間複雜度:O(n²) — visited 陣列和 BFS 佇列的大小均為 O(n²)。
1. Set n = board size, target = n * n
2. Define getCell(num):
a. Compute 0-indexed pos = num - 1
b. rowFromBottom = pos / n, col = pos % n
c. If rowFromBottom is odd, col = n - 1 - col (reverse direction)
d. r = n - 1 - rowFromBottom
e. If board[r][col] != -1, return board[r][col]; else return num
3. Initialize visited[1..n²] = false; mark visited[1] = true
4. Push cell 1 into BFS queue; steps = 0
5. While queue is not empty:
a. For each cell in current BFS level:
- Dequeue curr; if curr == target, return steps
- For dice = 1 to 6:
* next = curr + dice; if next > target, break
* next = getCell(next)
* If not visited[next]: mark visited, enqueue next
b. Increment steps
6. Return -1 (unreachable)方法一:Dijkstra 最短路徑 將每個格子視為圖的節點,每次骰子移動為邊(邊權均為 1)。用 Dijkstra 求從格子 1 到格子 n² 的最短路徑。由於邊權相同,效果等同 BFS,但實作較複雜,時間複雜度 O(n² log n²),不如 BFS 直接。
方法二:動態規劃(僅適用於無環情況)
若棋盤不存在從較大格子跳回較小格子的梯子(即有向無環圖),可用 DP 正向計算每格的最少步數。但由於蛇可能造成循環,一般情況下 DP 不適用,BFS 天然處理循環(透過 visited 陣列避免重複訪問)。
getCell 函數?需要注意哪些邊界情況?