Bellman-Ford算法及其隊列優化(SPFA)

1、算法概述算法

        Bellman-Ford算法解決的是通常狀況下的單源最短路徑問題。所謂單源最短路徑問題:給定一個圖G=(V,E),咱們但願找到從給定源結點s屬於V到每一個結點v屬於V的最短路徑。單源最短路徑問題能夠用來解決許多其餘問題,其中包括下面幾個最短路徑的變體問題。包括單目的最短路徑問題、單結點最短路徑問題、全部結點對最短路徑問題,這裏不詳細介紹。回到bellman-Ford,在這裏,邊的權重能夠爲負值。給定帶權重的有向圖G=(V,E)和權重函數W : E-->R,Bellman-Ford算法返回一個布爾值,以代表是否存在一個從源點能夠到達的權重爲負值的環路。若是存在這樣的環路,算法將告訴咱們不存在解決方案。若是沒有這種環路存在,算法將給出最短路徑和它們的權重。邊的權值能夠爲負數、實現簡單,缺點是時間複雜度太高,高達O(VE)。但算法能夠進行若干種優化,提升了效率。函數

     天然語言描述測試

對有向圖G(V,E),用貝爾曼-福特算法求以V_s爲源點的最短路徑的過程:優化

  • 創建dist[],表示目前已知源點到各個節點的最短距離,起始值dist[s]=0,其他皆爲\infty
  • 創建Pred[]Pred[]表示某節點路徑上的父節點,起始值皆爲NULL。
  • (V_i,V_j) \in E,比較dist[V_i]+(V_i,V_j)dist[V_j],並將小的賦給dist[V_j],若是修改了dist[V_j]pred[V_j]=V_i(鬆弛操做)
  • 重複以上操做V-1
  • 再重複操做一次,如dist[V_j]>dist[V_i]+(V_i,V_j),則此圖存在負權環。

    僞代碼表示
spa

BellmanFord(G,s)
 for i = 0 to n-1 do
  dist[i]= ∞
  Pred[i]= 0
 dist[s]=0
 for k = 1 to n-1 do
    foreach (V_i,V_j)E do
      if dist[V_i]+(V_i,V_j)<dist[V_j] do
          dist[V_j]=dist[V_i]+(V_i,V_j)
         Pred[V_j]=V_i
foreach (V_i,V_j)E do
      if dist[V_i]+(V_i,V_j)<dist[V_j] do
         return "No Shortest Path"
 return dist[]

2、原理htm

       爲何說最短路徑不存在負環呢?隊列

       若是圖G包含從s能夠達到的權重爲負值的環路,則最短路徑權重無定義。從s到該環路上的任意結點的路徑都不多是最短路徑,由於咱們只要沿着任何「最短」路徑再遍歷一次權重爲負值的環路,則老是能夠找到一條權重更小的路徑。若是從結點s到結點v的某條路徑上存在權重爲負值的環路,咱們定義s到v的最短路徑等於負無窮。
ip

        鬆弛操做get

        它的原理是對圖進行V-1次鬆弛操做,獲得全部可能的最短路徑。對於一條邊(u,v)的鬆弛過程爲:首先測試一下是否能夠對源點s到v的最短路徑進行改善。測試的方法是,將從結點s到結點u之間的最短路徑距離加上結點u與v之間的權重,並與當前的s到v的最短路徑估計進行比較,若是前者更小,則對v.d(源點s到v的最短路徑) 和v.π(前驅結點)進行更新。
it

        每次鬆弛操做其實是對相鄰節點的訪問,第n次鬆弛操做保證了全部深度爲n的路徑最短。因爲圖的最短路徑最長不會通過超過V-1條邊,因此可知貝爾曼-福特算法所得爲最短路徑。

        負邊權操做

        與迪科斯徹算法不一樣的是,迪科斯徹算法的基本操做「拓展」是在深度上尋路,用於有向無環圖的最短路徑算法對每條邊僅鬆弛一次。Bellman-Ford「鬆弛」操做則是在廣度上尋路,這就肯定了貝爾曼-福特算法能夠對負邊進行操做而不會影響結果。

       負權環斷定

        由於負權環能夠無限制的下降總花費,因此若是發現第n次操做仍可下降花銷,就必定存在負權環。

3、隊列優化——SPFA

       求單源最短路的SPFA算法的全稱是:Shortest Path Faster Algorithm。鬆弛操做一定只會發生在最短路徑前導節點鬆弛成功過的節點上,用一個隊列記錄鬆弛過的節點,能夠避免了冗餘計算。複雜度能夠下降到O(kE),k是個比較小的係數(而且在絕大多數的圖中,k<=2,然而在一些精心構造的圖中可能會上升到很高)

       實現方法:創建一個隊列,初始時 裏只有起始點,再創建一個表格記錄起始點到全部點的最短路徑(該表格的初始值要賦爲極大值,該點到他自己的路徑賦爲0)。而後執行鬆弛操做,用隊列裏有的點去刷新起始點到全部點的最短路,若是刷新成功且被刷新點不在隊列中則把該點加入到隊列最後。重複執行直到隊列爲空
      判斷有無負環:若是某個點進入隊列的次數超過N次則存在負環 (存在負環則無最短路徑,若是有負環則會無限鬆弛,而一個帶n個點的圖至多鬆弛n-1次 。 參考:算法導論、http://zh.wikipedia.org/zh-cn/%E8%B4%9D%E5%B0%94%E6%9B%BC-%E7%A6%8F%E7%89%B9%E7%AE%97%E6%B3%95#.E6.9D.BE.E5.BC.9B
相關文章
相關標籤/搜索