演算法筆記-3
三維迷宮問題
其實就是二維迷宮的推廣而已,可以同樣用 DFS 解決,此時每次可前進的方向會有 6 個,分別為前、後、上、下、左、右,而判斷邊界時也要注意 x, y, z 都要判斷。因為題目必須判斷最短時間,因此要多加一個變數 dis 來儲存當前的最短步數。
部分程式碼:
1 | //6個方向 |
圖的最短路徑問題
單源最短路徑 (Single Source)
確定起點,去求到其他點的最短路徑問題,根據邊的權重是否有負值必須選擇不同的演算法。
權重非負 - Dijkstra’s Algorithm
- 建立陣列 vis,初始值為 0 ,儲存該點是否已經確定最小距離。
- 建立陣列 dis,dis[S] 為 0,其他點皆為無限,代表 S 到該點目前的最小距離。
- 建立陣列 parent,紀錄到該點最短路徑的父節點。
- 從 vis = 0 的點中挑選 dis 最小的點 M,檢查其相鄰節點 N,假設 N 到 M 距離為 k ,取 dis[M] = min(dis[M] ,dis[N] + k),並將 vis[M] 標示為 1。
- 重複步驟 4 直到所有點皆被 visited。
實作:
1 | //假設該圖有 n 個節點,且所有節點連通,d[a][b] 儲存 a 到 b 的權重 |
如果要取得 S 到某點 P 的最短路徑,只要從 parent[P] 開始往回推直到 S 點。
權重為負 - Bellman-ford Algorithm
- 建立陣列 dis,dis[S] 為 0,其他點皆為無限,代表 S 到該點目前的最小距離。
- 建立陣列 parent,紀錄到該點最短路徑的父節點。
- 窮舉 S 到所有點 A 以及其鄰近點 B,假設 A 和 B 之間距離為 k,如果 dis[A] + k < dis[B],則進行 relax,設定 dis[B] = dis[A] + k。重複本步驟 (n - 1) 次,其中 n 為總結點數。
- 再次窮舉所有點進行檢查,如果可以 relax 代表存在負環。
實作:
1 | int relax(){ |
全域最短路徑 (All Pairs)
也稱為多源最短路問題,用於求圖中所有的最短路徑。
Floyd–Warshall Algorithm
窮舉所有節點 k ,將其作為中繼點,比較 dis[i][j] 和 dis[i][k] + dis[k][j] 的大小,如果經過 k 點會使距離更小則將其記錄下來。
1 | void floyd_warshall(){ |
注意本演算法的時間複雜度為 ,使用時須注意是否會超時。