spfa演算法及其應用和優化
by mps
【問題引入】
又是一年春運時,因為睡懶覺而導致搶不到票的你,只能打車回家了,而無疑會消耗許多錢財(黑車...),為了盡可能的節省錢,你希望走的是最短路,路途中會經過n個城市,而你每次經過兩個城市之間的高速公路時,都會損耗ci元,假設其中包含了所有的價錢(郵費,過橋費之類的),你現在在1號城市,希望到達n號城市去,請問最少花費是多少?
【輸入描述】
第一行,n,m,表示有n個城市,m條高速公路
第二行至第m+1行,每行三個數u,v,w,表示u城市到達v城市的耗費為w元(均為有向邊)
【資料範圍】
對於20%的資料,n≤100,m≤1,000
對於50%的資料,n≤1,000, m≤1,000
對於100%的資料,n≤10,000,m≤10,000
【分析】
題目其實並不難,乙個最短路的裸模板題目
但是資料卻讓初學者犯了難,很明顯出題人的意思是這樣的:
對於20分,是留給只會floyd的人
對於50分,是留給會dijkstra或者bellman_ford
對於100分,是留給會heap+dijkstra或者spfa+(slf/lll)
本文著重介紹spfa以及優化(slf/lll)
參考資料:
spfa演算法是基於bellman_ford演算法的改進,bellman_ford演算法的大致模板如下:
for(i=1->v)
for(j=1->e)
if(u,v (-e 且 e(u,v)+δu<δv)
δv=e(u,v)+δu
時間複雜度o(ve)
對於資料較大的情況(比如說例題)會tle,所以我們需要優化
那麼如何優化呢?
我們發現,每次沒有必要鬆弛m條邊,只需要鬆弛與當前節點有關的邊即可,但是又會有些節點脫離了拓撲關係,所以我們可以採用佇列/棧來維護拓撲關係
這樣我們的時間複雜度就降到了o(vk) 一般情況下k<2,但沒有絕對性的證明而且有針對性資料,所以除非迫不得已採用spfa(事實上出現迫不得已的情況就是因為出題人想讓你用spfa....)否則盡可能的採用高效率的dijkstra,實在不行弄個堆優化,要知道,堆優化的dijkstra是可以超過spfa的(而且絕對穩定)
而spfa用手動佇列寫起來有點煩,而我們c++的福利就在於stl為我們提供了絕對具有安全性的佇列,但是耗時間太長了,不過我們可以採用許多優化來彌補
具體有4種優化方案(1,3只能選1種)
(1)slf
設當前隊頭為i,即將入隊的點j,若δi≥δj,則直接將j入對頭,否則入隊尾,效率提公升10%~20%,需要資料結構雙端佇列
(2)lll(效率低下,這裡不贅述)
(3)prq
採取優先佇列,每次儲存距離小的,效率提公升20%~30%,與堆優化的dijkstra並肩
(4)math(適用於判斷負權環)
由於k的取值不定,有可能會非常多,所以對於判斷負權環就只能無奈的tle了,這時我們可以用隨機數生成乙個在題目條件下的最大最極端的資料,然後不斷地縮小n
(補充:判斷是否具有負權環只需判斷每個點的入隊次數是否>n)
到最後原本o(1000*1000)的演算法可能優化為o(1000*3)的演算法,不過本優化適宜rp好或者數學學霸使用
noip2014d2t2尋找道路
usaco 歡樂派對
usaco 騎馬修柵欄
另:最短路學好對以後的網路流問題有極大的幫助
SPFA演算法以及其優化
spfa演算法 shortest path faster algorithm 是經佇列優化的單源最短路bellman ford演算法通常用於求含負權邊的單源最短路徑,以及判負權環。spfa演算法最壞情況下複雜度和樸素的bellman ford演算法相同,為o ve 一般情況為o ke 其中k為常數,...
貝爾曼 福特最短路演算法及其優化(SPFA)
日常膜拜dalao 財神萬歲!日常凌晨水題解。我發誓這是我今天最後一篇部落格了。話說,我的部落格一般解釋全在 注釋裡面,而且講的不細緻。真的想詳細看模擬的話參見dalao的部落格 為什麼我們不用dijkstra演算法?因為,dijkstra無法處理負權邊的狀況 這個我這篇部落格不細講 而貝爾曼 福特...
SPFA及其優化 他復活了
spfa算是一種比較萬能的最短路演算法了 時間複雜度 o mn 特點 1.每個點可以入隊多次 2.不能處理負環,但可以判斷負環 3.佇列優化減少一些冗餘的鬆弛操作 貼乙個模板題 include include include include include include includeusing ...