Dijkstra求最短路

2021-10-10 22:27:59 字數 3379 閱讀 9136

如果圖中存在負權邊,則不要使用 dijkstra 來求最短路。

如果題目中表明所給的圖存在重邊與自環。

在求最短路徑的問題中,

如果自環邊權重是 正數,顯然它不會出現在最短路徑中。如果自環邊是 負數,則需要考慮出現在最短路中。

如果是稠密圖,使用了鄰接矩陣來存邊,則因為求最短路,所以我們對於重邊,只需要儲存最小的那個重邊即可。 但如果是稀疏圖,使用了鄰接表來存邊的話,則不需要對重邊進行特殊處理。

一般需要使用樸素版 dijkstra 演算法的圖論問題都是稠密圖,我們需要使用鄰接矩陣來存 邊。

使用乙個一維陣列 dist[i] 表示 i 號點到起點的距離,並且初始化 dist[1] = 0,其餘 dist 點初始化為 +

∞+\infty

+∞s 表示當前已確定最短距離的點。

以上過程的原理是貪心思想。

int

dijkstra()

}

s[t]

=true

;// 已經找到了乙個不在集合 s 中的距離最近的點 t,現在將它放入集合 s。

for(

int j =

1; j <= n;

++j)}if

(d[n]

==0x3f3f3f3f

)return-1

;// 說明沒有1 ~ n 的最短路

else

return d[n]

;}

for i 1 ~ n 迴圈了 n 次。確定不在 s 中的,距離最近的點,需要乙個 for 迴圈 n次 。用 t 更新其它點的距離也需要乙個 for 迴圈 n 次。因此,樸素版 dijkstra 演算法的時間複雜度是 o(n

2)o(n^)

o(n2

)。如果是乙個稀疏圖,且圖的點數超過 105

10^10

5 。樸素版 dijkstra 就會超時。應該使用 堆優化的 dijkstra,且用 鄰接表儲存圖。

首先分析樸素版 dijkstra 的效能瓶頸。

在 外層 for 迴圈下,尋找 「不在 s 中的,距離最近的點」,一共運算了 n2n^

n2次;「s (1

)o(1)

o(1)

。所以,一共運算了 n 次。

「用 t 更新其它點的距離」 因為 點 t 並非與所有點都有邊,每次 for 迴圈只會尋找 t 的相鄰點。所以整體上,一共運算了 m 次。

經過上述分析,我們知道,最耗時的步驟是 尋找 」不在 s 中的,距離最近的點。「

在一堆數中尋找最小的數字,我們可以使用來尋找。時間複雜度是 o(1

)o(1)

o(1)

。但是在堆中修改乙個數的時間複雜度是 o(l

ogn)

o(log n)

o(logn

) 。所以 」用 t 更新其它點的距離」 這一步每次都是 logn 。因此,堆優化的 dijkstra 演算法的時間複雜度是 o(m

logn

)o(mlog n)

o(mlog

n),其中 m 表示 邊數。

可以手寫堆,也可以使用 c++ stl 的優先佇列。但是兩者在實現和時間複雜度上有一點點小學問。

手寫堆的好處是 n 個點的堆只需要 n 個元素,並且修改 堆 中任意乙個元素的時間複雜度是 o(l

ogn)

o(log n)

o(logn

)。stl 優先佇列的好處是簡單、容易寫。但是由於底層實現是依靠冗餘,也就是意味著每次你使用 stl 優先佇列的修改操作實際上是直接在 堆 中插入乙個新的元素,因此空間複雜度是 o(m),m 表示邊數。所以,stl 優先佇列修改元素的時間複雜度是 o(log m)

但是,如果 m

mm 遠遠小於 n2n^

n2(稀疏圖),則 log m <= 2log n,時間複雜度還是 o(l

ogn)

o(log n)

o(logn

)。當你使用堆優化的 dijkstra 時,往往是因為點數 n 超過了 105

10^10

5 ,且是稀疏圖(你想想,如果點數超過 105

10^10

5 ,在演算法題中,往往不能用乙個二維陣列來存所有邊,因為空間不夠。)。因此,堆優化的 dijkstra 往往使用 stl 優先佇列,而不用手寫堆。

#include

#include

#include

#include

#include

using

namespace std;

typedef pair<

int,

int> pii;

const

int n =

150010

, m =

2* n;

int e[m]

, ne[m]

, idx, h[n]

, w[m]

;int n, m;

int d[n]

;bool st[n]

;void

init()

void

add(

int a,

int b,

int z)

intdijkstra_optimization_by_heap()

);// 將 1 號點放入堆中

while

(heap.

size()

));}

}}if(d[n]

==0x3f3f3f3f

)return-1

;else

return d[n];}

intmain()

int ans =

dijkstra_optimization_by_heap()

;if(ans !=-1

)printf

("%d\n"

, ans)

;else

puts

("-1");

}

參考:acwing

Dijkstra求最短路

題目鏈結 給定乙個n個點m條邊的有向圖,圖中可能存在重邊和自環,所有邊權均為正值。請你求出1號點到n號點的最短距離,如果無法從1號點走到n號點,則輸出 1。輸入格式 第一行包含整數n和m。接下來m行每行包含三個整數x,y,z,表示存在一條從點x到點y的有向邊,邊長為z。輸出格式 輸出乙個整數,表示1...

Dijkstra求最短路

題目鏈結 給定乙個n個點m條邊的有向圖,圖中可能存在重邊和自環,所有邊權均為非負值。請你求出1號點到n號點的最短距離,如果無法從1號點走到n號點,則輸出 1。輸入格式 第一行包含整數n和m。接下來m行每行包含三個整數x,y,z,表示存在一條從點x到點y的有向邊,邊長為z。輸出格式 輸出乙個整數,表示...

Dijkstra求最短路

1.通過dijkstra計算圖g中的最短路徑時,需要指定起點s 即從頂點s開始計算 2.此外,引進兩個集合s和u。s的作用是記錄已求出最短路徑的頂點 以及相應的最短路徑長度 而u則是記錄還未求出最短路徑的頂點 以及該頂點到起點s的距離 3.初始時,s中只有起點s u中是除s之外的頂點,並且u中頂點的...