单源最短路径之贝尔曼福特算法(Bellman-ford)及其队列优化算法SPFA算法

一、概述
贝尔曼-福特算法(Bellman–Ford),是求解单源最短路径(也就是找到从一个节点到图上其他所有节点的最短路径)问题的一种算法,由理查德·贝尔曼和莱斯特·福特创立。它的原理是对图进行次松弛操作,得到所有可能的最短路径。
常常拿它与Dijkstra算法作对比。Dijkstra算法也是用于求解单源最短路径的,但是当图中存在负权弧时,该算法就不适用了。而Bellman-ford算法恰恰可以解决这个问题。然而,Bellman-ford算法的时间复杂度过高,因此就有一些相应的优化算法来提高它的效率(SPFA算法)。

二、为什么Dijkstra不可以求解存在负权弧的问题?
如果图中存在负权环,Dijkstra算法在求解时就会陷入循环,因为它总能找到一个更短的路径。
让我们来举一个例子:
参考: link.(特别好的视频,是英文但是强烈推荐!)
1、负的自循环边
负权环出现的一种方式是负的自循环边,一旦陷入负的自循环,就会在这个负循环里循环无数次直到退出。而其他经过这个循环后可到达的点的最短路径就会变成负无穷大(点2,3,4,5)。
负的自循环边
2、总权值为负
由几个点组成的环的总权值为负(把该环中所有的边上的权值相加为负),经过这个循环可以到达的节点的最短路径为负无穷大(3,4,5)。
在这里插入图片描述
三、Bellman-ford算法的具体步骤
假设有n个点,m条边,s是起点。
1、定义一个距离数组d[n],除起点对应的d[i]初始化为0外,其余均初始化为正无穷。该数组用于记录从起点到各点的距离。(最后d[n]里面记录的就是从起点到各点的最短距离)
2、对d[n]进行n-1次的更新(因为在有n个点的情况下,最坏的情况,也就是到达最后一个点经过的边数最多的情况,共需要经过n-1条边)。
3、每一次更新时,找本次可以进行更新的点进行操作(但每条弧都要访问到)。在访问弧时,假设弧的起点为u,终点为v,权值为w,要看d[u]+w是否小于d[v],若满足,则更新d[v]为d[u]+w。

四、一种Bellman-ford算法的简单优化方式
在n-1次迭代中,若在第k次迭代时,d[n]不发生任何变化,则从这次开始,以后的每次迭代d[n]都不会再发生变化,也即已经求出了最短路径。可以通过插旗帜的方式来进行优化(即设一变量flag,并对该变量进行判断)。

五、Bellman-ford的队列优化算法——SPFA算法
上述Bellman-ford算法在每次迭代寻找能更新的值的时候,是很盲目的,每一次都会把m条边全部检查一遍。但其实每次并不需要去检查以上一次距离没有变化的点为起点的边(因为即便检查也不会满足更新条件)。因此,我们可以从这个角度出发,对Bellman-ford算法进行优化,这也就是SPFA算法。


我研究这个算法是为了求解“最小费用最大流问题”,因此并没有把这三种方式单独实现一遍,而是用SPFA直接编写了“最小费用最大流”的求解程序。所以这里就只整理它们的思路和原理啦~

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只柠檬柠檬精

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值