演算法導論小結 11 單源最短路徑問題

2021-05-01 10:50:20 字數 4091 閱讀 5020

by:

潘雲登

對於商業目的下對本文的任何行為需經作者同意。

寫在前面

1.本文內容對應《演算法導論》(第

2版)》第

24章。 2.

主要介紹了兩種求解單源最短路徑的演算法:

bellman-ford

演算法和dijkstra

演算法。 3.

最短路徑問題

在最短路徑問題中,給出的是乙個帶權有向圖

g=(v, e)

,加權函式w:

e->r

為從邊到實型權值的對映。路徑

p=0, v1, …, vk>

的權是指其組成邊的所有權值之和

w(p)

。可以定義從u到

v間的最短路徑的權為δ

(u, v)=min

。如果從u到

v不可達,則δ

(u, v)

為∞。一條最短路徑既不能包含負權迴路,也不會包含正權迴路。由於最短路徑問題具有最優子結構性質,即最短路徑的子路徑是最短路徑,因此可以利用

動態規劃或貪心演算法

的思想進行求解。單源最短路徑問題,在給定圖

g=(v, e)

的情況下,希望找出從某個給定源頂點

s∈v到每個頂點v∈v的最短路徑。

通常不僅希望算出最短路徑的權,而且希望得到最短路徑上的頂點。因此,可以對每個頂點v,設定其前趨頂點π[v],以便使源於頂點v的前趨鍊錶沿著從s到v的最短路徑的相反方向排列。由π的值匯出的前趨子圖gπ

=(vπ

, eπ

)定義為,vπ

=∪,即頂點集vπ

為g中所有具有非空前趨的頂點集合加上源點s;且eπ=

},即有向邊集eπ是v

π中的頂點的π值匯出的邊集。在單源最短路徑問題得解後,gπ

就是最短路徑樹,包含了從源點s到

s可達的每個頂點之間的一條最短路徑。

鬆弛操作

對每個頂點v∈

v,可以設定乙個屬性

d[v]

,用來描述從源點s到

v的最短路徑上權值的上界,稱為最短路徑估計。在初始化時,對所有v∈

v,有π[v]=null,對v∈

v-,有

d[s]=0

以及d[v]=

∞。在鬆弛一條邊

(u, v)

的過程中,要測試是否可以通過

u,對迄今找到的道

v的最短路徑進行改進;如果可以改進的話,則更新

d[v]

和前趨π[v]。鬆弛操作是單源最短路徑演算法中改變最短路徑和前趨的唯一方式。

void initalize_single_source(adjlist *graphic, int s)

graphic->distance[s] = 0;

}void relax(adjlist *graphic, int u, int v, int weight)

}

bellman-ford

演算法

bellman-ford

演算法能在存在負權邊的情況下,解決單源最短路徑問題,並且可以返回乙個布林值,表明圖中是否存在乙個從源點可達的負權迴路,這是它優於

dijkstra

演算法的地方。

bellman-ford

演算法:首先,對各個頂點的最短路徑估計

d和前趨

π進行初始化;然後,執行|v|-1次迴圈,每次迴圈中,利用鬆弛操作對所有邊的端點的

最短路徑估計

d和前趨

π進行更新;最後,通過判斷各頂點的

最短路徑估計是否收斂,表明是否存在負權迴路。由於第二步的迴圈需要

(|v|-1)|e|

次鬆弛操作,

bellman-ford

演算法的總執行時間為

o(ve)。

在演算法開始前,最短路徑樹中僅包含源點

s。第一趟迴圈過後,與

s相鄰的結點被加入到最短路徑樹中。在所有頂點可達的情況下,至多需要

|v|-1

次迴圈,便可將所有頂點加入到樹中。由於後加入的頂點與其前趨結點之間可能存在負權邊,因此,已經存在於樹中的路徑仍然可能被更新。換句話說,在不存在負權迴路的情況下,路徑

(s, v)

至多需要

|v|-1

次鬆弛操作,即可收斂到最短路徑的權

d[v]=

δ(s, v)

。這是因為在

|v|-1

次迴圈後,不會再有新結點引入負權邊,導致路徑

(s, v)

被更新。這也是檢查負權迴路是否存在的依據。

int bellman_ford(adjlist *graphic, int s)}}

for(j=0; jvertex_number; j++)

}return 1;

}bellman-ford

演算法的不足在於,每次迴圈過程中存在許多冗餘的鬆弛操作。一種改進的

spfa(shortest path faster algorithm)

演算法基於以下觀察:只有那些在前一趟迴圈中更新了最短路徑估計的頂點,才可能引起它們的鄰接點的最短路徑估計的改變。因此,

spfa

演算法用乙個佇列來存放被成功鬆弛的頂點。初始時,源點

s入隊。當佇列不為空時,取出隊首頂點,

對它的鄰接點進行鬆弛。如果某個鄰接點鬆弛成功,且該鄰接點不在佇列中,則將其入隊。經過有限次的鬆弛操作後,佇列將為空,演算法結束。但是,只有在不存在負權迴路的時候,

spfa

演算法才能正常工作。

dijkstra

演算法

dijkstra

演算法比bellman-ford

演算法的執行時間要低,但它要求所有邊的權值非負。

dijkstra

演算法中設定了乙個頂點集合

s,從源點

s到集合中的頂點的最終最短路徑的權值均已確定。演算法反覆選擇具有最短路徑估計的頂點

u∈v-s,並將u加入s中,對u的所有出邊進行鬆弛。由於總是在v-s中選擇「最近」的頂點插入集合s中,可以說

dijkstra

演算法使用了貪心策略。可以想象,在

dijkstra

演算法的執行過程中,最短路徑估計沿著以

s為根的最短路徑樹向下傳播。由於不存在負權邊,最短路徑樹中的邊一旦確定就不再改變。可以使用最小堆構建的最小優先佇列(同

prim

演算法),儲存集合

v-s中的頂點。

dijkstra

演算法需要

|v|次執行時間為

o(lg v)

的heap_extract_min

操作和|e|

次執行時間為

o(lg v)

的heap_decrease_key

操作,因此,總的執行時間為

o((v+e) lg v)

,如果所有頂點都從源點可達的話,則為

o(e lg v)。

void dijkstra(adjlist *graphic, int s)

build_min_heap(&h);

while(h.heap_size > 0)

*/temp_lnode = graphic->vlist[temp_vhnode->index].link;

while(temp_lnode != null)

}free_heap(&h);

}

單源最短路徑演算法小結

這裡就不寫具體演算法了,只將他們的時間複雜度 適用範圍 複雜程度簡單做個比較 待搜尋的圖都指有向圖 無向圖類似 儲存方式均為鄰接表 一 廣度優先搜尋 bfs 時間複雜度 o v e 效率很高 適用範圍 很窄 僅適於無權邊的圖。即每條邊長度都為1的情況 複雜程度 一般,需佇列 二 bellman fo...

演算法導論筆記 單源最短路徑

本文所貼示的偽 均 演算法導論 本文只是對其中 單源最短路徑 章節的簡單總結,許多數學證明過程已忽略。最短路徑的定義 給定乙個圖g v,e 希望找到從給定源節點s v 到每個結點v v 的最短路徑。單源最短路徑可以用來解決許多其他問題,包括 1 單目的地最短路徑問題 找到從每個結點v到給定目的結點t...

單源最短路徑演算法

簡單介紹 最短路徑演算法是圖演算法中的經典演算法,是用於解決圖中某個頂點到另外乙個頂點所經過路徑的花銷最小 這裡的花銷可能是時間也可能指費用等 dijkstra是用於解決單源最短路徑的經典演算法。圖的儲存方式 鄰接矩陣 在鄰接矩陣中,要獲取某個結點的出度和入讀,是通過掃瞄結點所在臨界矩陣中的行列完成...