SPFA算法

前言

\(SPFA\),全名\(Shortest-Path-Faster-Algorithm\),是\(Bellman-Ford\)算法的一種隊列優化版本.一般用於求含負權邊的單源最短路徑,以及判負權環。算法

但這種算法一直不被國際所承認,也沒有在專業的論文中被嚴格證實時間複雜度,因此部分毒瘤出題人會出卡\(SPFA\)的數據。數組


正文

由於是優化\(Bellman\)上來的,因此優化的是\(Bellman\)的最薄弱的地方--時間的浪費。優化

\(Bellman\)花費了太多時間在沒有做用的循環上,真正進行的鬆弛操做並很少,因此\(SPFA\)就用一個隊列來進行優化。如下是具體過程。spa

首先創建隊列,裏面存放待進行優化的結點,最初的元素爲根節點。開一個數組記錄元素是否已經在隊列中。隊列

當隊列不爲空時,取出隊首元素\(u\),並循環枚舉與\(u\)鏈接的點\(v\),判斷若是\(dis[v]>dis[u]+w\),即從\(u\)走向\(v\)比以前操做更優,那就更新\(dis[v]\)的值。知足條件以後,若是\(v\)不在隊列中,則把它加入隊列。記得添加/消除標記。it

每次更新結點的\(dis[]\)值稱爲一次鬆弛操做,若是一個結點被鬆弛達到\(n\)次,那麼這個圖中含有負權環。ast

\(SPFA\)\(bfs\)只有略微的差異,那就是\(SPFA\)中一個元素能夠反覆加入隊列,只要它知足條件,而\(bfs\)不會。class

穩定性不用說,稍微特殊構造數據就炸。test


至於各類優化?好比下面列的:(摘自知乎)原理

LLL 優化:每次將入隊結點距離和隊內距離平均值比較,若是更大則插入至隊尾。

Hack:向 1 鏈接一條權值巨大的邊,這樣 LLL 就失效了。

SLF 優化:每次將入隊結點距離和隊首比較,若是更大則插入至隊尾。

Hack:使用鏈套菊花的方法,在鏈上用幾個並列在一塊兒的小邊權邊就能欺騙算法屢次進入菊花。SLF 帶容錯:每次將入隊結點距離和隊首比較,若是比隊首大超過必定值則插入至隊尾。

SLF 帶容錯:每次將入隊結點距離和隊首比較,若是比隊首大超過必定值則插入至隊尾。

Hack:若是邊權之和很小的話彷佛沒有什麼很好的辦法,由於令邊權之和爲\(W\) ,那麼令容錯值爲\(sqrt(W)\) ,總複雜度彷佛接近 \(O((V+E)sqrt(W))\)。我不肯定這個複雜度對不對,可是 SPFA 確實在邊權和小的時候跑得蠻不錯的。因此卡法是卡\(SLF\)的作法,並開大邊權,總和最好超過\(10^12\)

mcfx 優化:在第\([L,R]\)次訪問一個結點時,將其放入隊首,不然放入隊尾。一般取\(L=2,R=sqrt(V)\)

Hack:網格圖表現優秀,可是菊花圖表現不好。P.S. 此優化與 SLF 帶容錯一塊兒使用有更好的效果,可使所須要的邊權上升許多。

SLF + swap:每當隊列改變時,若是隊首距離大於隊尾,則交換首尾。

Hack: 與卡 SLF 相似,外掛誘導節點便可。


從原理上來看,這些優化都是爲了讓隊列更加接近優先隊列,但維護一個優先隊列須要至少\(log\)級的時間複雜度(目前來看),因此低於這個時間複雜度級別的處理...總有能卡的吧..

即便如此,\(SPFA\)也不失爲考場上隨機對拍數據的一個幫手或者是時間不足時的備用方案,但若是沒有緊急狀況?乖乖背\(dij+heap\)吧。

相關文章
相關標籤/搜索