Bellman Ford 演算法及其優化

2021-06-20 13:37:18 字數 3475 閱讀 4688

**:

bellman-ford 

演算法及其優化

bellman-ford

演算法與另乙個非常著名的

dijkstra

演算法一樣,用於求解單源點最短路徑問題。

bellman-ford

演算法除了可求解邊權均非負的問題外,還可以解決存在負權邊的問題(意義是什麼,好好思考),而

dijkstra

演算法只能處理邊權非負的問題,因此

bellman-ford

演算法的適用面要廣泛一些。但是,原始的

bellman-ford

演算法時間複雜度為o(

ve),比

dijkstra

演算法的時間複雜度高,所以常常被眾多的大學演算法教科書所忽略,就連經典的《演算法導論》也只介紹了基本的

bellman-ford

演算法,在國內常見的基本資訊學奧賽教材中也均未提及,因此該演算法的知名度與被掌握度都不如

dijkstra

演算法。事實上,有多種形式的

bellman-ford

演算法的優化實現。這些優化實現在時間效率上得到相當提公升,例如近一兩年被熱捧的

spfa

(shortest-path faster algoithm 

更快的最短路徑演算法)演算法的時間效率甚至由於

dijkstra

演算法,因此成為資訊學奧賽選手經常討論的話題。然而,限於資料匱乏,有關

bellman-ford

演算法的諸多問題常常困擾奧賽選手。如:該演算法值得掌握麼?怎樣用程式語言具體實現?有哪些優化?與

spfa

演算法有關係麼?本文試圖對

bellman-ford

演算法做乙個比較全面的介紹。給出幾種實現程式,從理論和實測兩方面分析他們的時間複雜度,供大家在備戰省選和後續的

noi時參考。

bellman-ford

演算法能在更普遍的情況下(存在負權邊)解決單源點最短路徑問題。對於給定的帶權(有向或無向)圖g=(

v,e),其源點為

s,加權函式w是

邊集e 

的對映。對圖g執行

bellman-ford

演算法的結果是乙個布林值,表明圖中是否存在著乙個從源點s

可達的負權迴路。若不存在這樣的迴路,演算法將給出從源點s到

圖g的任意頂點

v的最短路徑

d[v]

。(1)    

初始化:將除源點外的所有頂點的最短距離估計值

d[v]

←+∞, d[s] ←0;

(2)    

迭代求解:反覆對邊集e中的每條邊進行鬆弛操作,使得頂點集v中的每個頂點v的最短距離估計值逐步逼近其最短距離;(執行|v|-1次)

(3)    

檢驗負權迴路:判斷邊集

e中的每一條邊的兩個端點是否收斂。如果存在未收斂的頂點,則演算法返回

false

,表明問題無解;否則演算法返回

true

,並且從源點可達的頂點

v的最短距離儲存在

d[v]中。

演算法描述如下:

bellman-ford(g,w,s) 

:boolean   //圖g 

,邊集函式w ,

s為源點

1        

for each vertex v

∈ v(g) do        //初始化 1階段

2        

d[v]

←+∞

3        

d[s] ←0;                             //1階段結束

4        

for i=1 to |v|-1 do               //2階段開始,雙重迴圈。

5        

for each edge(u,v) ∈e(g) do //邊集陣列要用到,窮舉每條邊。

6        

if d[v]> d[u]+ w(u,v) then      //鬆弛判斷

7        

d[v]=d[u]+w(u,v)               //鬆弛操作   2階段結束

8        

for each edge(u,v) ∈e(g) do

9        

if d[v]> d[u]+ w(u,v) then

10    

exit false

11    

exit true

下面給出描述性證明:

首先指出,圖的任意一條最短路徑既不能包含負權迴路,也不會包含正權迴路,因此它最多包含

|v|-1

條邊。

其次,從源點

s可達的所有頂點如果

存在最短路徑,則這些最短路徑構成乙個以

s為根的最短路徑樹。

bellman-ford演算法的迭代鬆弛操作,實際上就是按頂點距離s的層次,逐層生成這棵最短路徑樹的過程。

在對每條邊進行1遍鬆弛的時候,生成了從s出發,層次至多為1的那些樹枝。也就是說,找到了與s至多有1條邊相聯的那些頂點的最短路徑;對每條邊進行第2遍鬆弛的時候,生成了第2層次的樹枝,就是說找到了經過2條邊相連的那些頂點的最短路徑……。因為最短路徑最多隻包含|v|-1 條邊,所以,只需要迴圈|v|-1 次。

每實施一次鬆弛操作,最短路徑樹上就會有一層頂點達到其最短距離,此後這層頂點的最短距離值就會一直保持不變,不再受後續鬆弛操作的影響。(但是,每次還要判斷鬆弛,這裡浪費了大量的時間,怎麼優化?單純的優化是否可行?)

如果沒有負權迴路,由於最短路徑樹的高度最多只能是|v|-1,所以最多經過|v|-1遍鬆弛操作後,所有從s可達的頂點必將求出最短距離。如果 d[v]仍保持 +∞,則表明從s到v不可達。

如果有負權迴路,那麼第 |v|-1 遍鬆弛操作仍然會成功,這時,負權回路上的頂點不會收斂。

優化

1、使用標誌優化:

分析 bellman-ford演算法,不難看出,外層迴圈(迭代次數)|v|-1實際上取得是上限。由上面對演算法正確性的證明可知,需要的迭代遍數等於最短路徑樹的高度。如果不存在負權迴路,平均情況下的最短路徑樹的高度應該遠遠小於 |v|-1,在此情況下,多餘最短路徑樹高的迭代遍數就是時間上的浪費,由此,可以依次來實施優化。

從細節上分析,如果在某一遍迭代中,演算法描述中第7行的鬆弛操作未執行,說明該遍迭代所有的邊都沒有被鬆弛。可以證明(怎麼證明?):至此後,邊集中所有的邊都不需要再被鬆弛,從而可以提前結束迭代過程。這樣,優化的措施就非常簡單了。

設定乙個布林型標誌變數 relaxed,初值為false。在內層迴圈中,僅當有邊被成功鬆弛時,將 relaxed 設定為true。如果沒有邊被鬆弛,則提前結束外層迴圈。這一改進可以極大的減少外層迴圈的迭代次數。

2、使用佇列優化:

spfa (見下篇文章)

模版題:uva 

558 - wormholes

Bellman Ford 演算法及其優化

bellman ford 演算法與另乙個非常著名的 dijkstra 演算法一樣,用於求解單源點最短路徑問題。bellman ford 演算法除了可求解邊權均非負的問題外,還可以解決存在負權邊的問題 意義是什麼,好好思考 而 dijkstra 演算法只能處理邊權非負的問題,因此 bellman fo...

Bellman Ford演算法及其佇列優化與實戰入門

bellman ford演算法能解決負權邊的圖,就是說能夠來判斷存在負環。先來看一下核心 dis i 為源點到i點的最短路 for k 1 k n 1 k n為頂點的個數 for int i 1 i m i m為邊的條數 if dis v i dis u i w i u i 為第i條邊的起點,v i...

Bellman Ford演算法,SPFA演算法

bellman ford 演算法能在更普遍的情況下 存在負權邊 解決單源點最短路徑問題。對於給定的帶權 有向或無向 圖g v,e 其源點為 s,加權函式w是 邊集e 的對映。對圖g執行 bellman ford 演算法的結果是乙個布林值,表明圖中是否存在著乙個從源點s 可達的負權迴路。若不存在這樣的...