背景:
只是想來備份一下最近的**,順便總結一下三種最短路演算法的應用。
基礎**:
dijkstra:
1struct nd};
2int d[maxn]; bool vis[maxn]; priority_queueq;
3void dijkstra(int
s));
5while(!q.empty()));9}
10}11 }
spfa(bfs+slf):
1 ll d[maxn]; bool inq[maxn]; dequeq;2ll spfa()12}
13}14return
d[n];
15 }
spfa(dfs):
1bool ins[maxn],f; double
d[maxn];
2void dfs(int
x) d[es[i].t]=d[x]+es[i].w; dfs(es[i].t);8}
9}10 ins[x]=0;11
}12bool
spfa() return1;
15 }
floyd:
1 inc(k,1,n)inc(i,1,n)inc(j,1,n)if(map[i][k]+map[k][j]
比較:dijkstra:
本演算法的優點就是快,沒有什麼一定需要其解決的問題,且只能處理正權邊及求最短路(不能求最長路)。複雜度為o(mlog2n)不過常數會稍大。
spfa:
優點是可以處理負權邊以及判負環,當不用判負環時bfs+slf(雙端佇列優化)的最壞複雜度是o(nm),但是常數很小,有時快過dijkstra。當需要判負環時bfs+slf複雜度經常會達到最壞複雜度,這時候用dfs寫法會明顯快很多,因為在不連通圖中判負環需要每個點都作為源點跑一次。
floyd:
優點是短,可以用一行求出兩兩點的最短路,複雜度o(n3)且常數很小。
常見模型:
差分約束系統:
n個數,知道他們兩兩之間形如ai-aj≥c,ai-aj≤c的關係,求n個數最小/最大是多少。解法:如果是求最大值,則將所有限制條件轉化為為≤,將得到的i和j連邊,權值為c並跑最短路,因為得到的是滿足條件的最大值;如果是求最小值,則將所有限制條件設定為≥,將得到的i和j連邊,權值為c並跑最長路,因為得到的是滿足條件的最小值。
01分數規劃:
n點m邊有向圖,點有點權,邊有邊權,從某點出發,走一些路使得經過的點權和除以(浮點數除法)邊權和最大或最小,求這個小數(保留兩位)。解法:假設需要所求小數最大,那麼二分這個數,然後將所有邊的邊權改為分母(需要最小化的部分)*二分的數-分子(需要最大化的部分),然後判負環。如果有,說明解合法,否則解不合法。最後把下界輸出。如果需要所求小數最小,則把邊權改為分子(需要最大化的部分)-分母(需要最小化的部分)*二分的數,同時改變範圍縮小的方向。
倍增floyd:
從s到t,要求剛好經過k條邊,求最短路。解法:把用floyd的方式對兩個鄰接矩陣進行合併定義成乙個運算,則答案為初始矩陣與自己做k次運算得到的結果。而該運算符合結合律,故可以用類似矩陣快速冪的方法剛好做log2k次運算。
最短路總結
寫個部落格記錄一下最短路的幾種演算法,盡量做最正確的解答,減少大家的疑惑,網上有好多講的都抄來抄去,還有好多講的都是錯誤的。熟悉的最短路演算法就幾種 bellman ford,dijkstra,spfa,floyd,下面針對這幾個演算法具體解析一下。首先說明一點,就是關於負環的問題。bellman ...
最短路總結
穿越空間的限制,走最短的路找到你 u v之間的最短路滿足以下限制 對任意k g v,e 有 dist u,v dis u,k dis k,j 關鍵操作 鬆弛 void relax int i,int j,int k floyd void floyd 複雜度o v 3 可處理負環 拓展把所有邊存成負的...
最短路總結
首先是dij演算法,這是我第乙個掌握的最短路演算法!再來是bellman ford演算法,這個演算法比較容易理解,而且考慮到了負環的存在。記住,它對圖中的邊進行了 v 1次操作!首先,對d進行初始化 還有乙個spfa演算法 摘錄於學長空間 設立乙個先進先出的佇列用來儲存待優化的結點,優化時每次取出隊...