最短路模板:dij,spfa与floyd
圖論技能get!
一個超強大的建圖網站
最短路問題
1.dij算法
用于單源最短路
僅適用于沒有負邊權的情況
初始化dis數組為inf,dis【起點】=0;
tool:priority-queue(按dis升序)
先把起點放進隊列
每次取出排頭now,枚舉它能去的地方v;
如果——
說明目前從now走到v更優,就更新它,并入隊
最后now出列,并永遠不要回來(用人話說就是判重)
模板
void dij(){for(int i=1;i<=n;i++) dis[i]=INT_MAX;memset(jd,0,sizeof(jd));dis[s] = 0;priority_queue<pr,vector<pr>,greater<pr> >q;q.push(make_pair(0,s));int tot=0;while(!q.empty()){int now=q.top().second;q.pop();if(jd[now]) continue;jd[now]=1;for(int i=fi[now];~i;i=p[i].nxt){int v=p[i].to;//printf("#%d %d %d\n",p[i].nxt,now,v);if(dis[v]>dis[now]+p[i].w){dis[v]=dis[now]+p[i].w;q.push(make_pair(dis[v],v)); }}} }(關于鏈式前向星存圖,請移步這里
證明
因為沒有負權
所以當前dis最小的值以后不可能從別的地方再更新
所以每次都取最小的,每個就只需取一次(n)
備注
因為優先隊列操作復雜度帶個log,所以
總復雜度為:O(nlogn)
從證明也可以看出,dij只適用于正權,那么有負權是怎么辦?
可以使用——
2.SPFA
“spfa已經死了”
和dij其實很類似,只是他不用優先隊列,也不判重,只要枚舉出度滿足上面那個關系式就可以進隊(當然,已經在的不要再進了)
當隊列為空結束
代碼
void spfa(double x){queue<int>q;mem(jd,1);for(int i=1;i<=n;i++) dis[i]=(double)inf;mem(nm,0);for(int i=0;i<m;i++){p[i].w -= x;}for(int i=1;i<=n;i++){q.push(i);}while(!q.empty()){int now=q.front();q.pop();jd[now]=0;for(int i=fi[now];~i;i=p[i].nxt){int v=p[i].to;if(dis[v]>=dis[now]+p[i].w){dis[v]=dis[now]+p[i].w;if(jd[v]==0) q.push(v);}}}for(int i=0;i<m;i++) p[i].w +=x;return; }證明
因為不去重,隊列還是空了,說明已經沒有任何兩對滿足更新的關系式~~(暴力有什么好證明的)~~
備注
復雜度十分 玄學 不穩定
在特殊構造和稠密圖可能卡成O(mn)
直接裂開(2018NOIP血的教訓)
所以盡量還是用dij吧
floyd
多源!!!!
代碼《過于冗長》,直接看著代碼解釋吧。。。
代碼
for(int k = 1; k <= n; ++k)for(int i = 1; i <= n; ++i)for(int j = 1; j <= n; ++j)dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);證明
(想不明白直接背)
dp[i][j][k]是從i到j經過中轉編號最大值為k的最短路
那么dp[i][j][k]更新到dp[i][j][k+1]就是看看經過k+1會不會更優唄
所以就是上面那個狀態轉移方程
最后dp[i][j][n]就是最終的最短路
踩蛋
(這個不是王建國寫的)
負環
如果存在一個總權值為負值的環,那么所有能碰到該環的兩點的最短路都會是無窮小(大風車吱吖吱悠悠的轉 )
此時spfa就會出現死循環
所以需要特殊判斷負環
如果一條路徑經過的點大于n,顯然它是經過了環
而你算著算著最短路它為啥溜號去跑環了呢?一定是出現了負環
從而進行判斷
關于代碼實現,我們可以在更新時加一行轉移:
代碼
bool spfa(){queue<int>q;mem(jd,0);for(int i=1;i<=n;i++) dis[i]=inf;mem(nm,0);q.push(1);jd[1]=1;dis[1]=0;while(!q.empty()){int now=q.front();q.pop();jd[now]=0;for(int i=fi[now];~i;i=p[i].nxt){int v=p[i].to;if(dis[v]>dis[now]+p[i].w){dis[v]=dis[now]+p[i].w;nm[v]=nm[now]+1;if(jd[v]==0) q.push(v);if(nm[v]>=n){return true;}}}}return false; }覺得明白了可以來洛谷水道模板
就醬!拜拜~
總結
以上是生活随笔為你收集整理的最短路模板:dij,spfa与floyd的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 车子补漆去4S店还是去修理厂好些汽车补漆
- 下一篇: 图论:dij算法优化:双端队列及详细证明