简单介绍一下\(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; }