**:
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 可達的負權迴路。若不存在這樣的...