shortest path algorithm —— Bellman–Ford
Bellman–Ford
Bellman–Ford 算法是一种单源最短路径算法,用于计算一个顶点到其他所有顶点的最短路径。
算法思想
Bellman–Ford 算法的基本思想是:就是不断尝试对图上每一条边进行松弛。我们每进行一轮循环,就对图上所有的边都尝试进行一次松弛操作,当一次循环中没有成功的松弛操作时,算法停止。
松弛操作(relaxation)
:松弛操作是指对于一条边e
,我们试图通过这条边来缩短起点到终点的距离。如果dis[a] + w < dis[b]
,那么我们就可以通过这条边来缩短起点到终点的距离,即dis[b] = dis[a] + w
。
算法步骤
初始化:创建一个一维数组
dis
,用于存储起点到各点的最短路径长度,初始化为无穷大,起点到自己的距离为0。循环:对图上所有的边进行
n-1
轮松弛操作。判断负环:如果第
n
轮仍然有松弛操作,说明图中存在负环。返回结果:
dis[i]
即为起点到终点的最短路径长度。为什么第二步是
n-1
轮松弛操作?因为最短路径最多包含
n-1
条边,所以进行n-1
轮松弛操作后,所有的最短路径都会被计算出来。如果第二步是
n
轮松弛操作,那么就无法判断负环,因为负环的最短路径包含n
条边,所以进行n
轮松弛操作后,负环的最短路径长度仍然会被更新。
1 | struct Edge { |
复杂度分析
时间复杂度:$O(nm)$
每一轮循环中,我们对图上所有的边都进行了一次松弛操作,所以总共进行了
n-1
轮循环,每一轮循环中,我们对图上所有的边都进行了一次松弛操作,所以总共进行了m
次松弛操作,所以时间复杂度为$O(nm)$。空间复杂度:$O(n)$
我们只需要一个一维数组
dis
来存储起点到各点的最短路径长度,所以空间复杂度为$O(n)$。
队列优化(SPFA)
队列优化的 Bellman–Ford 算法又称为 SPFA(Shortest Path Faster Algorithm),是对 Bellman–Ford 算法的一种优化。
SPFA 算法的基本思想是:在 Bellman–Ford 算法中,我们每进行一轮循环,就对图上所有的边都尝试进行一次松弛操作,但是实际上,只有那些在上一轮循环中被松弛过的边,才有可能在这一轮循环中继续被松弛。所以我们可以用一个队列来存储这些在上一轮循环中被松弛过的边,这样就可以减少不必要的松弛操作。
算法步骤
- 初始化:创建一个一维数组
dis
,用于存储起点到各点的最短路径长度,初始化为无穷大,起点到自己的距离为0。 - 循环:将起点加入队列,对队列中的每一条边进行松弛操作,如果松弛成功,就将这条边的终点加入队列。
- 判断负环:如果某个顶点入队次数超过
n
次,说明图中存在负环。 - 返回结果:
dis[i]
即为起点到终点的最短路径长度。
1 | struct Edge { |
复杂度分析
时间复杂度:$O(nm)$
每一轮循环中,我们对队列中的每一条边都进行了一次松弛操作,所以总共进行了
m
次松弛操作,所以时间复杂度为$O(nm)$。空间复杂度:$O(n)$
我们只需要一个一维数组
dis
来存储起点到各点的最短路径长度,一个一维数组st
来存储顶点是否在队列中,所以空间复杂度为$O(n)$。