算法導論 - 第24章 單源最短路徑

單源最短路徑的算法有兩種:Bellman-Ford算法和Dijkstra算法。求最短路徑,如果最短路徑上存在weight小於0的cycle,則不存在最短路徑。因爲只要在這個cycle上多循環幾次,該路徑的weight就會降低。因此求最短路徑的weight時,應該判斷最短路徑上是否存在weight小於0的cycle,如果存在weight小於0的cycle,則無法對該圖求最短路徑,因爲沒有意義。

假設源點爲s。在每個頂點中保存一個變量用來保存到源點s的最短路徑的weight。爲方便,用d(u)來表示頂點u到源點s的最短路徑的weight。初始值都設爲正無窮大,源點s的d值設爲0。Bellman-Ford算法和Dijkstra算法的過程就是不斷更新每個頂點的d值,直到最小。w(u,v)表示邊(u,v)的weight。

函數Relaxation(int u,int v)用來更新頂點的d值。

void Relaxation(int u,int v)
{
    if(d(v)>d(u)+w(u,v))
    {
        d(v) = d(u)+w(u,v);
    }
}


Bellman-Ford算法可以判斷是否存在weight小於0的cycle。而Dijkstra只能在所有的edge的weight都大於等於0的網上運行。

1 Bellman-Ford算法

假設路徑(s,p1)(p1,p2)(p2,p3)(p3,p4)(p4,p5)...(pn-1,pn)是頂點s到pn的最短路徑。顯然,該路徑也必然是到中間頂點的最短路徑。即(s,p1)(p1,p2)(p2,p3)必然是s到p3的最短路徑。因此,假如我們按這個edges的順序計算p1,p2,p3,p4...pn的d值,只需計算一次就可以得到源點到pn的最短路徑的weight。

但我們事先不可能知道到每個頂點的最短路徑。所以不可能正好按照最短路徑的順序來計算每個頂點的最短路徑的weight值。但我們要注意到,如果我們打亂順序來更新px的d值,p1的d值肯定能被正確得計算。如果我們再來一次隨機更新所有頂點的d值,p2頂點的d值也能被正確地計算。如此,我們重複n遍,就能把該路徑上所有頂點的d值都計算出來。

考慮到源點s到任何頂點的最短路徑都不會超過n-1,我們只需要進行n-1次遍歷就可以。


2 Dijkstra算法

Dijkstra算法只需將所有的邊遍歷一次就能算的所有頂點到源點的最短路徑的weight。Dijkstra法將所有的頂點分爲兩個集合A和B:A是已經得到正確d值的頂點,B是還沒算的d值得頂點。剛開始時,A只包括頂點s。B包括所有其他的頂點。對所有以s爲尾的邊調用Relaxation,更新與之相連的頂點的d值。然後從B中所有的頂點中選出最小的d值的頂點v,加入到A中,並對所有以v爲尾的邊調用Relaxation。如此循環,直到所有的頂點都加入到A中。

該算法的關鍵是如何快速從B中選出最小d值的頂點。由於只需要選出最小d值的頂點,因此集合B用最小堆來實現最合適。

它的計算步驟爲:

1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章