算法思路
建立一个队列,初始时队列里只有起始点,再建立一个数组记录起始点到所有点的最短路径。然后执行松弛操作,用队列里有的点作为起始点去刷新到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空
SPFA 在形式上和BFS非常相似,不同的是BFS中一个点出了队列就不可能再次进入队列之中,而SPFA中 一个点可能在出队列之后再次进入队列之中,就是说一个点用于更新其他之后,如果其本身被更新,需要重新加入至队列之中,与其相连的点亦需重新更新。
spfa算法可用SLF和LLL优化
代码
代码中采用了链式前向星存边 查看链式前向星
#include<iostream>
#include<queue>
#include<cstdio>
#define inf 0x3f3f3f
using namespace std;
struct edge //边
{
int to,w,next;
}e[500001];
int head[100001],vis[100001],dis[100001],rd[100001],cnt,n,m,s;
queue<int>q;
void add(int u,int v,int w) //存边
{
e[++cnt].to=v;
e[cnt].w=w;
e[cnt].next=head[u];
head[u]=cnt;
}
void spfa()
{
for(int i=1;i<=m;i++) //每个点到起点距离赋初值无穷大
dis[i]=inf;
dis[s]=0;
vis[s]=1; //进入队列标记
q.push(s); //起点压入队列,先遍历与起点直接相连的点
rd[s]++;
while(q.size()) //队列为空终止
{
int u=q.front();
q.pop();
vis[u]=0; //出列清除标记
for(int i=head[u];i;i=e[i].next)//遍历与u相连的点
{
int v=e[i].to;
if(dis[v]>dis[u]+e[i].w) //距离变小,更新
{
dis[v]=dis[u]+e[i].w;
if(rd[v]>n) //判断负环
return;
if(!vis[v]) //如果距离更新,且被更新的点不在队列中,将其入列
{
q.push(v);
vis[v]=1; //入列标记
rd[v]++;
}
}
}
}
}
int main()
{
cin>>n>>m>>s;
int u,v,w;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
spfa();
for(int i=1;i<=n;i++) //输出到所有点的最短距离
cout<<dis[i]<<" ";
return 0;
}