簡單介紹一下\(SPFA\):先把全部點的值賦爲INF,而後找到起點,標位零,將其壓入隊列(都到這裏了,應該沒人不會隊列了吧…),下面的步驟要循環經行,直到隊列爲空。找到延生出來的節點,若是節點的值大於當前的點的值加邊的長度(設當前節點的值是\(v_i\),延伸出來的點的值是\(v_j\),邊的長度是\(d_i\),則上面那句話的意思是若是\(v_i\)+\(d_i\)>\(v_j\)),就更新並加入隊列。
具體實現就是這個亞子:
看到第三幅圖的那個箭頭了嗎?那裏是不能加入隊列的,由於隊列裏已經有4號點了,這是\(SPFA\)最容易打錯的地方。
(圖片來源於洛谷2019夏令營的課件)
這裏再說一下有關\(SPFA\)的其餘的東西:c++
接下來是最激動人心的時刻:上代碼!!!spa
#include<bits/stdc++.h> using namespace std; int n,m,s; queue<int>q; bool f[10005];//用於標記是否加入隊列 int v[10005];//每一個點離起點的最短路徑 struct graph { int tot; int hd[10005]; int nxt[500005],to[500005],dt[500005]; void add(int u,int v,int w) { tot++; nxt[tot]=hd[u]; hd[u]=tot; to[tot]=v; dt[tot]=w; return ; } }g; int main() { scanf("%d%d%d",&n,&m,&s); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); g.add(u,v,w); } memset(v,0x3f,sizeof(v));//初始化,初始化必須是一個很大的值,不然若是實際路徑比初始化長就會出問題 v[s]=0; f[s]=true; q.push(s); while(!q.empty())//直到隊列爲空爲止 { int xx=q.front(); q.pop();//取出第一個元素並彈出 f[xx]=false;//標記爲沒有加入隊列 for(int i=g.hd[xx];i;i=g.nxt[i])//枚舉該節點延伸出來的點 if(v[g.to[i]]>v[xx]+g.dt[i])//鬆弛操做 { if(!f[g.to[i]]) q.push(g.to[i]),f[g.to[i]]=true;//加入隊列 v[g.to[i]]=v[xx]+g.dt[i];//更新 } } for(int i=1;i<=n;i++) if(v[i]!=1e10) printf("%d ",v[i]); else printf("2147483647 "); return 0; }