最短路徑Dijkstra演算法
阿新 • • 發佈:2022-11-30
最短路徑
最短路徑的性質:
- 路徑是有向的
- 權重不一定等價於距離,權重也可以指時間,花費或者其他
- 並不是所有頂點都是可達的
- 負權重會使得問題更復雜(Dijkstra演算法不適用於這種情況)
- 最短路徑一般都是簡單的,這裡演算法會忽略構成環的零權重邊,找到的最短路徑都不會有環
- 最短路徑不一定是唯一的
- 可能存在平行邊和自環
最短路徑樹:給出起點s,計算結果是一顆最短路徑樹(Shortest Path Tree SPT),它包含了頂點s到所有可達頂點的最短路徑
資料結構:
- 最短路徑樹中的邊edgeTo[],edgeTo[v]表示s到v的最短路徑中的最後一條邊
- 到達起點的距離distTo[],distTo[v]表示s到v的已知最短路徑長度
Dijkstra 演算法
取自<演算法>第四版-演算法4.9
該演算法類似Prim及時演算法
private double[] distTo; // distTo[v] = distance of shortest s->v path private DirectedEdge[] edgeTo; // edgeTo[v] = last edge on shortest s->v path private IndexMinPQ<Double> pq; // priority queue of vertices public DijkstraSP(EdgeWeightedDigraph G, int s) { // 起點到各個頂點v的距離 distTo = new double[G.V()]; // 起點到各個頂點v最短路徑中的最後一條邊 edgeTo = new DirectedEdge[G.V()]; // 初始化起點s到各個頂點的距離為無窮最大值 for (int v = 0; v < G.V(); v++) { distTo[v] = Double.POSITIVE_INFINITY; } distTo[s] = 0.0; // 從s到頂點v的權重為優先順序 pq = new IndexMinPQ<Double>(G.V()); // s為起點 pq.insert(s, distTo[s]); while (!pq.isEmpty()) { // 取出頂點v int v = pq.delMin(); // 遍歷頂點v的各個邊 for (DirectedEdge e : G.adj(v)) { relax(e); } } } // 鬆弛一個頂點,判斷起點s到頂點w的最短路徑是否是s -> v -> w private void relax(DirectedEdge e) { // 邊e為從頂點v到頂點w的有向邊 int v = e.from(), w = e.to(); // 如果s到w的距離大於s到v + v到w的距離,則更新該距離,並將頂點w存入優先順序佇列 if (distTo[w] > distTo[v] + e.weight()) { distTo[w] = distTo[v] + e.weight(); edgeTo[w] = e; // 如果佇列中已存在頂點w,則需要更新s到頂點w的距離,也即是更新權重 if (pq.contains(w)) { pq.decreaseKey(w, distTo[w]); } else { pq.insert(w, distTo[w]); } } } // 判斷起點s到頂點v是否可達 public boolean hasPathTo(int v) { return distTo[v] < Double.POSITIVE_INFINITY; } // 獲取起點s到頂點v的最短路徑 public Iterable<DirectedEdge> pathTo(int v) { if (!hasPathTo(v)) { return null; } Stack<DirectedEdge> path = new Stack<DirectedEdge>(); for (DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()]) { path.push(e); } return path; }
空間複雜度:V
時間複雜度:ElogV
給定兩點s->t的最短路徑:可使用Dijkstra演算法並在優先佇列中取到t之後終止搜尋
任意頂點之間的最短路徑:遍歷各個頂點構造最短路徑樹,時間及空間複雜度均為EVlogV
加權無環圖
加權無環圖:加權有向圖中不含有有向環的圖
可線上性時間內解決加權無環圖中的最短路徑問題,比Dijkstra演算法更快
- 可線上性時間內解決單點最短路徑問題
- 能夠處理負權重的邊
待補充...
負權重的加權有向圖
負權重的加權有向圖:可能含有環也可能含有負權重的邊的加權有向圖
Bellman-Ford演算法:時間複雜度EV,空間複雜度V
大佬自行研究去吧,我該curd去了