EndlessLethe原创文章,转载请注明: 转载自小楼吹彻玉笙寒

前言

Bellman-Ford算法,限于资料匮乏和时间复杂度比Dijkstra算法高,包括白书在内的很多资料,都没说得太明白。对于优化后的SPFA算法也没有提及。

而且最短路问题通常是作为图论的入门问题,学习者通常没有图论基础,不知道图论的一些基本常识,看已有的资料很容易产生疑惑。其实,从Bellman-ford算法优化到SPFA算法实际上是顺理成章的。

本文旨在阐明这两个算法思想和步骤,如果有什么晦涩或者疏漏之处在所难免,烦劳读者们指出。

Bellman-Ford算法有什么用

Bellman-Ford算法是用来解决单源最短路问题的。

在现实生活旅游途中,我们通常想知道一个景点到其他所有景点的最短距离,以方便我们决定去哪些比较近的景点。而这时候,Bellman-Ford算法就有用了。

Bellman-Ford算法的优点是可以发现负圈,缺点是时间复杂度比Dijkstra算法高。

而SPFA算法是使用队列优化的Bellman-Ford版本,其在时间复杂度和编程难度上都比其他算法有优势。

算法流程

(1)初始化:将除起点s外所有顶点的距离数组置无穷大 d[v] = INF, d[s] = 0

(2)迭代:遍历图中的每条边,对边的两个顶点分别进行一次松弛操作,直到没有点能被再次松弛

(3)判断负圈:如果迭代超过V-1次,则存在负圈

我们用距离数组d[i]来记录起点s到点i的最短距离。

看了上面的算法流程,通常我们会有四个问题:

1. 什么是松弛操作

2. 迭代多少次?

3. 迭代的实际意义是什么?

4. 为什么迭代超过v-1次就存在负圈?

直观理解松弛操作

如图,假设选取边<3,4>来进行松弛操作,那么进行两次如下操作(w为边权):

d[3] = min(d[3], d[4]+w) // 对点3

d[4] = min(d[4], d[3]+w) // 对点4

这样做的目的是让距离数组d尽量的小。

而每一次让d[i]减小的松弛操作,我们都称其“松弛成功”。

而实际中,我们使用的松弛操作可以是选取一条边,也可以是从一个点from到另一个点to。后者对应的松弛操作为:

d[to] = min(d[to], d[from] + w)

从最短路的角度来讲,如果对点3的松弛操作成功,意味着从s到4再从4到3这条路比其他从s到3的路都短,距离数组中的d[3]就是目前起点到点3的最短距离。

我们可以总结为:每一次成功的松弛操作,都意味着我们发现了一条新的最短路。

直观理解迭代

第二第三个问题实际上都是同一个问题:迭代的实际意义是什么?

这里我先给出迭代的定义:每次都遍历图中的所有边,对每条边(的两个端点)都进行松弛操作。

下面,我们以上图中的点和边为例,讲清楚迭代的实际意义:

第一次迭代

我们很轻易的就找到了两点对应的最短路。

第二次迭代

我们又找到了新的三个点对应的最短路。

从这次迭代中,我们可以发现一个定理:只有上一次迭代中松弛过的点才有可能参与下一次迭代的松弛操作。

这里的“参与”指让邻点距离数组d[i]改变。

这个定理很容易理解,如果两个点的距离数组d[i]在上一次迭代后没有改变,那么这次也不会改变。只有上一次改变了的点才会影响周围的点。

第三次迭代

这次的示意图比上两次都要复杂许多,我给每条边都标注上了权值,不同迭代中改变过值的点也用不同颜色标注了出来。每条松弛过的边我也标注了出来。

我们重点注意边<3,4>中的点3被松弛了,图中标注为一条虚线。

回忆一下前面的内容,这意味着,我们发现了点3新的最短路,这个最短路经历了3条边。

这里揭示了迭代的实际意义:每次迭代k,我们找到了经历了k条边的最短路。

值得注意的是,在迭代还没结束时的最短路不一定是最终的最短路。有可能最终的最短路经历的边很多,但每条边的权值很小,比经历边少的路线距离更短。

第四次迭代

第五次迭代

第六次迭代

注意到没有点能够被松弛,根据之前发现的定理“只有上一次迭代中松弛过的点才有可能参与下一次迭代的松弛操作”,因为不再存在能够被松弛的点了,迭代结束。

总结定理一:只有上一次迭代中松弛过的点才有可能参与下一次迭代的松弛操作

迭代的实际意义:每次迭代k中,我们找到了经历了k条边的最短路。

“没有点能够被松弛”时,迭代结束

根据定理一“只有上一次迭代中松弛过的点才有可能参与下一次迭代的松弛操作”,似乎算法中遍历每条边的做法比较菜,我们只需要考虑那些被成功松弛的点的邻点不就好了吗?答案是肯定的。我们可以简单地通过一个队列来维护这些被成功松弛的点,这个小小的改进可以带来巨大加速,改进之后的算法被称为SPFA。

直观理解负圈

符合常识地,有定理二:如果在边权都为正的图中,最短路一定是一条路径,而不是一个圈,且长度不会大于等于V

拓展到存在负边权的图中,有定理三:对于存在负圈的图,最短路无意义

定理四:对于不存在负圈的图,最短路一定是一条路径,且长度不会大于等于V

如图所示,因为有边长为1、-2、-1的负圈存在,起点到其余所有点的距离都是-INF,因为到其余所有点的路上都可以经过这个负圈无穷次,这时候最短路没有意义。

对于Bellman-Ford算法,因为一个最短路如果不存在负圈的话,不会经历超过V-1条边,所以假如迭代次数大于等于V,就存在负圈。

Note:网上很多代码没有理解每次迭代的意义,采用每个节点的入队次数来判断负圈,当然也是可以,但是大大增加了运行时间。

写在最后

在SPFA的基础上,我们或许还能进行一些优化,比如参考文献表中的SLF和LLL,这里我就不多提了,有兴趣可以看一下,就一两行代码的事。

希望大家看完本文能够完全理解SPFA。

Bellman-ford实现代码

因为这道题点比较少,就使用了邻接矩阵来储存图。实际上,用得比较多的储存方法是邻接表和前向星,有兴趣了解的戳——“浅谈图的组织(邻接表、前向星)”【TBC】

SPFA实现代码

题目总结POJ 3259

有重边,使用邻接矩阵要注意。算法本身不在乎重边的情况,使用邻接表的话,对于虫洞直接添加一条新的边即可

POJ 1860

参考文献

c语言bellman算法,深入理解Bellman-Ford(SPFA)算法相关推荐

  1. openCV中直方图均衡化算法的理解

    直方图均衡化就是调整灰度直方图的分布,即将原图中的灰度值映射为一个新的值.映射的结果直观表现是灰度图的分布变得均匀,从0到255都有分布,不像原图那样集中.图像上的表现就是对比度变大,亮的更亮,暗的更 ...

  2. 快速平方根倒数算法深度理解

    快速平方根倒数算法深度理解 快速平方根倒数算法是什么? 简单来说这个算法避开了开方和除法运算快速实现了 y = 1 x y= \frac{1}{\sqrt x} y=x ​1​ 快速平方根倒数算法首次 ...

  3. 关于最短路径算法的理解

    "最短路径算法:Dijkstra算法,Bellman-Ford算法,Floyd算法和SPFA算法等.​从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路 ...

  4. 最短路径:Dijkstra、BellmanFord以及SPFA算法

    最短路径问题 1.Dijkstra算法 简介 (1)Dijkstra算法伪代码 (2)C++ 邻接表版代码 (3)优化 (4)题型分析 2.Bellman Ford算法 简介 (1)Bellman算法 ...

  5. 【白话机器学习】算法理论+实战之K-Means聚类算法

    1. 写在前面 如果想从事数据挖掘或者机器学习的工作,掌握常用的机器学习算法是非常有必要的,常见的机器学习算法: 监督学习算法:逻辑回归,线性回归,决策树,朴素贝叶斯,K近邻,支持向量机,集成算法Ad ...

  6. 【白话机器学习】算法理论+实战之K近邻算法

    作者1. 写在前面 如果想从事数据挖掘或者机器学习的工作,掌握常用的机器学习算法是非常有必要的,在这简单的先捋一捋, 常见的机器学习算法: 监督学习算法:逻辑回归,线性回归,决策树,朴素贝叶斯,K近邻 ...

  7. k近邻算法_【白话机器学习】算法理论+实战之K近邻算法

    1. 写在前面 如果想从事数据挖掘或者机器学习的工作,掌握常用的机器学习算法是非常有必要的,在这简单的先捋一捋, 常见的机器学习算法: 监督学习算法:逻辑回归,线性回归,决策树,朴素贝叶斯,K近邻,支 ...

  8. 白话机器学习算法理论+实战之K近邻算法

    1. 写在前面 如果想从事数据挖掘或者机器学习的工作,掌握常用的机器学习算法是非常有必要的,比如我之前写过的一篇十大机器学习算法的小总结,在这简单的先捋一捋, 常见的机器学习算法: 监督学习算法:逻辑 ...

  9. Bellman算法和SPFA算法

    Dijkstra算法比较快速,但是如果遇到负边就无能为力了,而Bellman算法可以解决负边问题,只要不是负环. 这个算法数据结构没有讲过,他主要是每次对所以边进行松弛操作,进行n-1次得到最短路径. ...

最新文章

  1. 企业级微服务架构统一安全认证设计与实践!
  2. JavaScript中的Try...Catch 语句
  3. 我用ASP.NET缓存之OutputCache
  4. 7篇必读ACM MM 2019论文:图神经网络+多媒体
  5. opencv图像深度-1_OpenCV空间AI竞赛之旅(第1部分-初始设置+深度)
  6. 开源项目GoodView点赞效果
  7. python包numpy_NumPy Python科学计算软件包的终极指南
  8. 思科c240 m3 服务器安装系统,2U机架式 思科UCS C240 M3让你心动
  9. C语言 semaphore
  10. 造成美国断网的“凶手论坛”,终于关闭了DDoS版块
  11. 掌握Spark机器学习库-06-基础统计部分
  12. 【整理】牛客网编程题-前端篇(入门难度)
  13. 在IDEA上部署Robocode
  14. sqlhelper java_java 版本SQLHelper
  15. pytorch搭建卷积神经网络【第三课_自己搭建对抗神经网络】
  16. 测度论与概率论基础学习笔记7——3.1积分的定义
  17. java 文件存在 覆盖_java – 如果文件存在于目录中,我该如何覆盖它
  18. 现代材料分析方法习题汇总及答案
  19. 逃脱只会部署集群系列 —— jenkins和gitlab的部署联动推送
  20. 图片查看器插件(带缩略图) - viewer.js

热门文章

  1. 决策树算法——ID3算法,C4.5算法
  2. 阿里云发布黑科技:面对海量的文本翻译任务,阿里翻译团队是如何解决的
  3. 【产业互联网周报】网信办:不得利用算法影响网络舆论;华为任命丁耘为企业BG总裁;上海市布局数字经济、元宇宙等新赛道...
  4. 本Blog独立站点米豆网开通了
  5. 毕业季好难抉择丨考研还是工作我该选哪一个?!
  6. Type-C边充电边OTG芯片LDR6028A
  7. python微信公众号秒杀代码_微信跳一跳辅助python代码实现
  8. python自学行吗知乎_怎么自学python,大概要多久?
  9. Qt for winrt结合Winrt API开发
  10. 伦敦 quant_伦敦统一用户组(LUUG)见面v1.0