什么是SPFA算法
SPFA 算法是Bellman-ford算法的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。
前置知识:Bellman-ford算法详解_真的没事鸭的博客-CSDN博客
SPFA算法思路
SPFA算法其实就是在Bellman-ford算法基础上的优化。Bellman-ford算法看起来比较傻,每次迭代的话是遍历所有边来更新,但是每次迭代的话不是每条边都会更新。SPFA算法就是对这个做优化,每次迭代dist[b]可以更新的话,一定是dist[a]变小了,因为如果dist[a]不变的话,dist[b]一定不变。只有dist[a]变小了,它的后继才会变小。所以SPFA算法就从这个点进行优化。
SPFA算法的思路就是迭代的时候用一个队列来做,队列里面存的就是到起点距离变小的点。先把起点放到队列里面去,只要队列不空,也就是队列里面还有距离变小的点的话,就执行一下操作:
- 先取出队头t,然后队头出队
- 更新t的所有出边,t到起点的距离不是变小了吗, 那么所有和t相连的点都有可能变小,如果更新成功的话,就入队。但是注意要判断一下这个点已经入过队的话就不用重复加入了。
补充
SPFA算法的时间复杂度一般是O(m),最坏情况下时O(nm)。一般正权图我们是用Dijkstra算法去做,但是其实大部分的正权图的问题都可以用SPFA算法来做。不过出题人卡复杂度的话可能就用不了。所以SPFA算法是由Bellman-ford算法优化来的,不过长得特别像Dijkstra算法。
案例
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。
请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出
impossible
。数据保证不存在负权回路。
输入格式
第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
输出格式
输出一个整数,表示 1 号点到 n 号点的最短距离。
如果路径不存在,则输出
impossible
。数据范围
1≤n,m≤1e5
图中涉及边长绝对值均不超过 10000。输入样例:
3 3 1 2 5 2 3 -3 1 3 4
输出样例:
2
来源:ACWing文章来源:https://www.toymoban.com/news/detail-422195.html
思路
这个和Dijkstra堆优化版的代码相似,就是用队列优化了一下。文章来源地址https://www.toymoban.com/news/detail-422195.html
代码实现
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N=1e6+10;
int h[N],e[N],ne[N],idx,w[N];//邻接表,w数组表示权重,idx是两个点之间的桥梁
int n,m;
int dist[N];//每个点距离起点的距离
bool st[N];//判断这个点是否入队
//邻接表模板
void add(int a,int b,int c)
{
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
int spfa()
{
//初始化距离,1号点距离为0
memset(dist,0x3f,sizeof dist);
dist[1]=0;
//初始一个队列,用来存距离变小的点
queue<int>q;
q.push(1);//起点入队
st[1]=true;
while(q.size())//队列不空
{
int t=q.front();//取出队头
q.pop();//队头出队
st[t]=false;
//遍历它的所有出边,如果能更新的话就更新并且入队
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];//取得出点
if(dist[j]>dist[t]+w[i])//如果可以更新的话
{
dist[j]=dist[t]+w[i];//更新这个点距离起点的距离
if(!st[j])//判断是否在队中,不在的话入队
{
st[j]=true;
q.push(j);
}
}
}
}
return dist[n];
}
int main()
{
cin>>n>>m;
//初始化h数组
memset(h,-1,sizeof h);
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
//这里不考虑重边
add(a,b,c);
}
if(spfa()==0x3f3f3f3f)
cout<<"impossible";
else
cout<<spfa();
return 0;
}
到了这里,关于SPFA算法详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!