如果圖中存在負權邊,則不要使用 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
)。
如果是乙個稀疏圖,且圖的點數超過 10510^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中頂點的...