最短路

最短路

1. 知识结构图:

在这里插入图片描述
说明

  1. 约定:n为点数,m为边数。
  2. 上面当所有边权为正数时,有两种选择:1. 朴素Dijkstra算法;2. 堆优化版的Dijkstra算法。当稠密图时(m和n^2相当),尽量使用前者;当稀疏图时,使用后者堆排序版的Dijkstra算。
  3. SPFA一般情况下,比Bellman-Ford要快。但如果求的是“对边数做一个限制,经过的边数<=k的话,就无法使用SPFA算法,只能使用Bellman-Ford算法。”

2. 侧重点

以后遇到的最短路问题,不会让你证明算法的正确性。难点是让你建图,如何将原问题抽象成一幅图,如何定义点和边,使得问题变成最短路问题,然后套用模板来做。即难点在建图,不在算法的原理上

其它补充知识:Dijkstra算法,基于贪心;Floyd算法,基于动态规划;Bellman-Ford算法,基于离散数学的知识。

3. 朴素Dijkstra算法

算法流程:

  1. 初始化距离。1号点到起点的距离初始化为0,其它点距离都初始化为正无穷。dist[1] = 0, dist[i] = INF。
  2. 迭代n次。
    for v : 1 ~ n
    2.1 寻找不在s中的距起点距离最近的点t。【s:当前已确定最短距离的点】
    2.2 将t放到s中。s = t。
    2.3 用t更新其它所有点的距离。比如:针对某点j,使用 从起点到t加上从t到j的距离 更新 从起点到j的距离

算法模板:
【AcWing——最短路-朴素Dijkstra】AcWing 849. Dijkstra求最短路 I

4. 堆优化版的Dijkstra算法

首先:堆优化版的Dijsktra算法适合稀疏图。

堆优化版的Dijkstra算法,对朴素版的Dijkstra算法中步骤2.1、2.3,使用堆(优先队列)的数据结构对其进行了实现。另外,因为是稀疏图,存储图采用邻接表的方式实现。

具体来看的话:

  1. 朴素版的时间复杂度主要来自于步骤2.1,寻找距离最近的点t时遍历全部节点n,时间复杂度是O(n)。而使用堆时,这个操作是O(1)的。
  2. 朴素版步骤2.3更新所有点的距离时,复杂度为O(n),而使用堆来实现时,这个操作为O(mlogn)【堆操作此时是遍历邻近的所有边O(m),然后堆上进行push复杂度O(logn)】。

算法模板
【AcWing——最短路-堆优化版的Dijkstra算法】AcWing 850. Dijkstra求最短路 II

5. Bellman-Ford算法

算法流程

在这里插入图片描述
在这里插入图片描述
说明
从算法流程中可以看出,Bellman-Ford算法的时间复杂度为O(n*m)。

就两重循环,第一重循环n次,第二重循环所有边(上图中a, b, w代表:a到b的边权重为w),每次循环的时候更新一下最短距离就可以了。更新之后,该算法证明了所有边的距离一定满足dist[b] <= dist[a] + w,这个不等式称为三角不等式。遍历所有边更新的过程称为松弛操作

要注意一点,Bellman-Ford算法是处理有负权边的最短路问题。而求最短路时,如果有负权回路时,最短路是不一定存在的。 比如下面:从1开始走,走到2时,没走一遍2->3->5->2这个回路,权值都会减1,所以这样走下去最短路变为了负无穷。
所以如果图里面有负权回路的话,Bellman-Ford算法求出来的结果将会变为负无穷。(也就是说,能求出最短路的话,题里面肯定是没有负权回路的)。

但其实Bellman-Ford算法是可以求出来图中是否有负权回路的。上面算法流程中第一层循环迭代的此时实际上是有实际意义的。比如迭代k次之后,我们求的最短距离(dist数组)代表从1号点经过不超过k条边走到每个点的最短距离。 所以如果迭代的时候,第n次迭代的时候又更新了某些边的话,那就说明存在一条最短路,它上面的边数是大于等于n的, 也就有n+1个点,而1~n只有n个点,又抽屉原理知,一定有两个点编号一样,那这条路径上就一定存在环。路径上存在环,它是更新过后出现的,所以这个环一定是负环。
所以如果第n次迭代的时候,有边更新的话,那说明存在边数为n的最短路径,就说明存在负环。但一般找负环不是用Bellman-Ford算法来做(时间复杂度比较高),而是用SPFA来做。
在这里插入图片描述
算法模板:
【AcWing——Bellman_Ford算法】AcWing 853. 有边数限制的最短路

6. SPFA

SPFA是对bellman-ford算法的优化(使用宽度优先搜索)。
在这里插入图片描述

算法流程
在这里插入图片描述
算法模版
【最短路——SPFA】AcWing 851. spfa求最短路

此外,还可以使用SPFA判断负环。使用下方的cnt变量辅助。
在这里插入图片描述
判断负环例题:【最短路——Bellman_Ford算法】AcWing 853. 有边数限制的最短路

7. Floyd算法

Floyd可用于求多源最短路。它可以处理负权,但不能有负权回路。
算法流程:
在这里插入图片描述
Floyd算法基于动态规划,代码很简单,就三重循环。
在这里插入图片描述
在这里插入图片描述
算法模版:
【最短路——Floyd算法】AcWing 854. Floyd求最短路

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值