SPFA 算法介绍
SPFA 算法是 Bellman-Ford算法的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA 最坏情况下复杂度和朴素 Bellman-Ford 相同,为 O(VE)。
算法的思路:
(转自https://blog.youkuaiyun.com/qq_35644234/article/details/61614581)
我们用数组dis记录每个结点的最短路径估计值,用 邻接表 或 邻接矩阵 来存储图G。我们采取的方法是动态逼近法:
设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止
我们要知道带有负环的图是没有最短路径的,所以我们在执行算法的时候,要判断图是否带有负环,方法有两种:
- 开始算法前,调用拓扑排序进行判断(一般不采用,浪费时间)
- 如果某个点进入队列的次数超过N次则存在负环(N为图的顶点数)
SPFA算法手动操作过程
(转自https://blog.youkuaiyun.com/qq_35644234/article/details/61614581)
下面我们采用SPFA算法对下图求v1到各个顶点的最短路径,通过手动的方式来模拟SPFA每个步骤的过程
- 初始化:
首先我们先初始化数组dis如下图所示:(除了起点赋值为0外,其他顶点的对应的dis的值都赋予无穷大,这样有利于后续的松弛)
此时,我们还要把v1如队列:{v1}
现在进入循环,直到队列为空才退出循环。
- 第一次循环:
首先,队首元素出队列,即是v1出队列,然后,对以v1为弧尾的边对应的弧头顶点进行松弛操作,可以发现v1到v3,v5,v6三个顶点的最短路径变短了,更新dis数组的值,得到如下结果:
我们发现v3,v5,v6都被松弛了,而且不在队列中,所以要他们都加入到队列中:{v3,v