本文主要講解求單源最短路徑的Bellman-Ford算法。
Bellman-Ford算法
Bellman-Ford算法能夠在一般情況下,解決單源最短路徑問題。允許圖中出現權爲負數的邊。該算法還會返回一個布爾值。如果布爾值爲false,表示途中存在從源點可達的權爲負的迴路。
首先介紹一下鬆弛計算。如下圖:
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
鬆弛計算之前,點B的值是8,但是點A的值加上邊上的權重2,得到5,比點B的值(8)小,所以,點B的值減小爲5。這個過程的意義是,找到了一條通向B點更短的路線,且該路線是先經過點A,然後通過權重爲2的邊,到達點B。
當然,如果 出現一下情況
則不會修改點B的值,因爲3+4>6。
Bellman-Ford算法可以大致分爲三個部分
第一,初始化所有點。每一個點保存一個值,表示從原點到達這個點的距離,將原點的值設爲0,其它的點的值設爲無窮大(表示不可達)。
第二,進行循環,循環下標爲從1到n-1(n等於圖中點的個數)。在循環內部,遍歷所有的邊,進行鬆弛計算。
第三,遍歷途中所有的邊(edge(u,v)),判斷是否存在這樣情況:
d(v) > d (u) + w(u,v)
則返回false,表示途中存在從源點可達的權爲負的迴路。
之所以需要第三部分的原因,是因爲,如果存在從源點可達的權爲負的迴路。則 應爲無法收斂而導致不能求出最短路徑。
考慮如下的圖:
經過第一次遍歷後,點B的值變爲5,點C的值變爲8,這時,注意權重爲-10的邊,這條邊的存在,導致點A的值變爲-2。(8+ -10=-2)
第二次遍歷後,點B的值變爲3,點C變爲6,點A變爲-4。正是因爲有一條負邊在迴路中,導致每次遍歷後,各個點的值不斷變小。
在回過來看一下bellman-ford算法的第三部分,遍歷所有邊,檢查是否存在d(v) > d (u) + w(u,v)。因爲第二部分循環的次數是定長的,所以如果存在無法收斂的情況,則肯定能夠在第三部分中檢查出來。比如
此時,點A的值爲-2,點B的值爲5,邊AB的權重爲5,5 > -2 + 5. 檢查出來這條邊沒有收斂。
所以,Bellman-Ford算法可以解決圖中有權爲負數的邊的單源最短路徑問。