帶有負權邊的最短路徑問題


2018-03-13 17:08:57

最短路徑問題是圖論中一個經典的問題,Dijkstra算法更是大名鼎鼎。然而縱是如此著名的算法也有其不擅長的領域,也就是帶有負權邊的圖是無法使用Dijkstra算法來進行最短路計算的。理由也很簡單,每次dijkstra都是將目前的額最短路添加到集合中,這也就保證了,下一次的最短路徑是肯定要長於之前添加進去的最短路徑的,然而在有負權邊的時候,這個推論就會被打破,最后會導致整個Dijkstra算法崩潰。

那么,難道帶有負權邊的最短路徑問題就沒有解法了么?

答案顯然是否定的,這里就會介紹兩種求解帶有負權邊的圖的最短路徑求解的算法,一是Bellman Ford算法,二是SPFA算法

一、Bellman Ford算法

貝爾曼-福特算法(英語:Bellman–Ford algorithm),求解單源最短路徑問題的一種算法,由理查德·貝爾曼(Richard Bellman) 和 萊斯特·福特 創立的。有時候這種算法也被稱為 Moore-Bellman-Ford 算法,因為Edward F. Moore 也為這個算法的發展做出了貢獻。它的原理是對圖進行V-1次松弛操作,得到所有可能的最短路徑。其優於迪科斯徹算法的方面是邊的權值可以為負數、實現簡單,缺點是時間復雜度過高,高達O(VE)。但算法可以進行若干種優化,提高了效率。

Bellman Ford算法每次對所有的邊進行松弛,每次松弛都會得到一條最短路徑,所以總共需要要做的松弛操作是V - 1次。在完成這么多次松弛后如果還是可以松弛的話,那么就意味着,其中包含負環。

procedure BellmanFord(list vertices, list edges, vertex source)
   // 該實現讀入邊和節點的列表,並向兩個數組(distance和predecessor)中寫入最短路徑信息

   // 步驟1:初始化圖
   for each vertex v in vertices:
       if v is source then distance[v] := 0
       else distance[v] := infinity
       predecessor[v] := null

   // 步驟2:重復對每一條邊進行松弛操作
   for i from 1 to size(vertices)-1:
       for each edge (u, v) with weight w in edges:
           if distance[u] + w < distance[v]:
               distance[v] := distance[u] + w
               predecessor[v] := u

   // 步驟3:檢查負權環
   for each edge (u, v) with weight w in edges:
       if distance[u] + w < distance[v]:
           error "圖包含了負權環"

 

二、SPFA算法

求單源最短路的SPFA算法的全稱是:Shortest Path Faster Algorithm。 SPFA算法是西南交通大學段凡丁於1994年發表的。松弛操作必定只會發生在最短路徑前導節點松弛成功過的節點上,用一個隊列記錄松弛過的節點,可以避免了冗余計算。復雜度可以降低到O(kE),k是個比較小的系數(並且在絕大多數的圖中,k<=2,然而在一些精心構造的圖中可能會上升到很高)。

SPFA算法可以認為是對Bellman Ford算法的優化,但不論如何,這是在最短路徑問題中由中國學生提出的算法,算法的核心思路並不復雜,主要的操作就是維護一個candidate隊列,最開始的時候只有s,然后對s的鄰接邊進行松弛,如果可以松弛,則判斷一下當前結點是否在隊列中,如果不在的話,那么將該結點加入隊列,重復操作,知道隊列為空。

從理性的角度來分析這個算法的合理性:

只要最短路徑存在,上述SPFA算法必定能求出最小值。證明:每次將點放入隊尾,都是經過松弛操作達到的。換言之,每次的優化將會有某個點v的最短路徑估計值d[v]變小。所以算法的執行會使d越來越小。由於我們假定圖中不存在負權回路,所以每個結點都有最短路徑值。因此,算法不會無限執行下去,隨着d值的逐漸變小,直到到達最短路徑值時,算法結束,這時的最短路徑估計值就是對應結點的最短路徑值。

SPFA判環:

當一個結點入隊次數到達V的時候,表明其中有環。如同Bellman Ford算法,只需要V - 1次就可以完成所有的松弛,如果做了 V 次松弛,那么說明有環。

具體實現中可以用一個數組保存每個結點的入隊次數。

 procedure Shortest-Path-Faster-Algorithm(G, s)
  1    for each vertex v ≠ s in V(G)
  2        d(v) := ∞
  3    d(s) := 0
  4    offer s into Q
  5    while Q is not empty
  6        u := poll Q
  7        for each edge (u, v) in E(G)
  8            if d(u) + w(u, v) < d(v) then
  9                d(v) := d(u) + w(u, v)
 10                if v is not in Q then
 11                    offer v into Q

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM