spfa (shortest path faster algorithm)
是一種單源最短路徑的演算法,基於bellman-ford演算法上由佇列優化實現。
也就是說,bellman_ford是一種無腦,瘋狂鬆弛的演算法。其複雜度為o(nm),可想而知,對於上萬的資料會炸的一塌糊塗。。。
相對而言,spfa顯得就沒那麼無腦了。
在bellman_ford演算法上,我們找到了一種優化鬆弛的方法:對於其子邊沒有進行鬆弛的鬆弛操作,當前操作不可能得出正確結果,只能需要後期子邊全部被鬆弛為最佳結果後再進行鬆弛得到當前邊的最佳結果。
那麼,在理解這個後,我們搞乙個佇列來優化bellman_ford。具體的,對於已經被鬆弛過的點,我們將其入隊去更新其他的點,這樣相對於原來用沒有被優化更新的點去更新其他點來說更優。在當前點優化完其他點後,將其出隊,以後也可以進隊,用來優化其他邊。如此迴圈往復直到隊列為空(沒有可以優化的點了),那麼求出來的就是最短路。
**,**於單源最短路徑弱化版。
//判斷負環:luogu-judger-enable-o2
#include#include
#include
#include
#define spfa zhx_ak_ioi
using
namespace
std;
const
long
long inf=2147483647
;long
long
n,m,s;
long
long dis[10008],vis[10001],head[10001],num_edge=0
;struct
edgeedge[
500008
]; queue
long>q;
void addedge(long
long
from,long
long to,long
long
dis)
void
spfa()
dis[s]=0
; vis[s]=1
; q.push(s);
while(!q.empty())}}
}}int
main()
spfa();
for(long
long i=1;i<=n;++i)
return0;
}
spfa和bellman_ford演算法可以用來判斷負環。
負環,就是圖上乙個邊權權值和為負數的環,
bfs廣搜判斷方法
對於乙個不存在負環的圖,從起點到任意乙個點最短距離經過的點最多只有n個。那麼定義乙個cnt陣列,表示當前點從起點(編號設為1)到點i的最短距離包含點的個數。如果乙個cnt的值大於n的話,就可以判斷負環了。同樣的,對於每一次鬆弛操作,一旦鬆弛成功,我們就將下乙個點的cnt值+1,對於環,我們每次鬆弛時直接判斷cnt值是不是大於n,如果大於,說明找到了負環,那麼我們就可以退出直接輸出就行。
但是,在找負環時,廣搜的性質決定了它的複雜度上並不適合找負環。原因:負環本質上是一條環形鏈(可以這麼想但不一定嚴謹。),但是bfs考慮面太廣了以至於在判環的操作上會考慮其他的不屬於這個環的元素,因此搜完整個環的效率會變慢。那麼有什麼演算法能夠在遍歷到這條鏈?的時候能夠不分心的一口氣走到底呢?dfs。
**就是在原spfa上加入cnt和判斷操作。
dfs深搜判斷負環方法
與bfs唯一不同就是把佇列換成了棧,取剛更新的點一口氣繼續更新到底。這樣就可以一直在環上跑,幾圈下來就可以判斷並退出了。。
**就是把bfs**上換個資料結構。
你問我為什麼這個**中沒有出現有關邊的負權的判斷?
在這上面
如果是負數的話那個條件就可以無限滿足並**圈圈跑)了。
完結。qwq
模板 Spfa判負環
給定乙個n個點m條邊的有向圖,圖中可能存在重邊和自環,邊權可能為負數。請你判斷圖中是否存在負權迴路。輸入格式 第一行包含整數n和m。接下來m行每行包含三個整數x,y,z,表示存在一條從點x到點y的有向邊,邊長為z。輸出格式 如果圖中存在負權迴路,則輸出 yes 否則輸出 no 資料範圍 1 n 20...
spfa(判負環變形)
題目鏈結 題意 n種貨幣,m種交換 s v 邊 u v r1 c1 r2 c2表示u貨幣換成v貨幣需要c1手續費和交換率r1,v換u為c2,r2.轉換公式 val v val u c1 r1 初始有s貨幣v枚。問能否通過一系列的交換,可以獲得比初始更多的錢?解法 include include in...
TT 的美夢(SPFA判負環)
這一晚,tt 做了個美夢!在夢中,tt 的願望成真了,他成為了喵星的統領!喵星上有 n 個商業城市,編號 1 n,其中 1 號城市是 tt 所在的城市,即首都。喵星上共有 m 條有向道路供商業城市相互往來。但是隨著喵星商業的日漸繁榮,有些道路變得非常擁擠。正在 tt 為之苦惱之時,他的魔法小貓咪提出...