Bellman-Ford 算法
Bellman-Ford 算法解析
Bellman-Ford 算法是一种用于计算单源最短路径的算法,适用于图中存在负权边的情况。它能够解决存在负权环的图,并且在处理时较为简单。本文将详细介绍 Bellman-Ford 算法的原理、步骤及为什么需要进行 n-1 次松弛操作。
1. 算法简介
Bellman-Ford 算法基于松弛操作(Relaxation)来找到最短路径。松弛操作是指通过一条边更新节点的最短路径估计值,只有当新的路径更短时才更新。算法通过对每一条边进行 n-1 次松弛操作,最终得到图中所有节点的最短路径。
2. 算法步骤
- 初始化: 
 将源节点到源节点的距离设为 0,其他节点到源节点的距离设为无穷大。
- 松弛操作: 
 对图中的每一条边进行松弛操作- n-1次。在每次松弛时,如果当前路径通过某条边可以提供更短的路径,则更新目标节点的距离。
- 检查负权环: 
 再次进行一次松弛操作,如果有边的松弛操作仍然可以更新距离,说明图中存在负权环。
3. 为什么 Bellman-Ford 需要进行 n-1 次松弛操作?
3.1 最短路径的性质
在图中,最短路径是由一系列的边组成的。对于一个包含 n 个节点的图,最短路径最多只会包含 n-1 条边。为什么是 n-1 条边?这是因为最短路径不会包含环,且在最短路径的计算中,最多需要经过图中的 n-1 条边。
3.2 逐步松弛过程
- 第一次松弛操作:每个节点只能通过一条边连接到源节点。
- 第二次松弛操作:每个节点可以通过两条边连接到源节点,依此类推,最多 n-1次松弛操作,每次都能够计算并更新通过更多边的最短路径。
3.3 为什么不是 n 次?
如果你进行了 n 次松弛操作,实际上不再有意义。原因是,最短路径最多只有 n-1 条边。如果在第 n 次松弛操作时,仍然能够更新某个节点的最短路径,说明图中存在负权环。负权环的存在使得最短路径可以不断缩短,因此无法计算出正确的最短路径。
3.4 松弛操作的核心
在 Bellman-Ford 算法中,每一次松弛操作都会将当前路径更新为最短路径。经过 n-1 次松弛操作后,我们能够保证所有节点的最短路径已经被正确计算。如果图中没有负权环,所有节点的最短路径已经找出,不需要继续松弛。
4. 负权环的检测
Bellman-Ford 算法的一个重要特性是能够检测图中的负权环。在进行 n-1 次松弛操作之后,如果再进行一次松弛操作,并且某条边的最短路径仍然可以被更新,说明图中存在负权环。负权环导致最短路径无法稳定,因此 Bellman-Ford 算法通过这种方式来检测图中是否存在负权环。
5. 示例代码
下面是 Bellman-Ford 算法的 Go 语言实现:
| 1 | package main | 
6. 总结
Bellman-Ford 算法是一种用于单源最短路径的经典算法,能够处理带有负权边的图,并且可以检测负权环。我们需要进行 n-1 次松弛操作来确保最短路径的正确计算,超过 n-1 次松弛操作可能会暴露负权环的存在,从而帮助我们进一步分析图的结构。
7 Bellman-Ford 使用示例
LeetCode 743: 网络延迟时间
题目要求的是:从某个节点 K 发出信号,计算信号到达所有节点的最短时间。如果某些节点无法接收到信号,返回 -1。
题目描述
给定一个图,图中的节点标号为 1 到 n,且图中的每条边都有一个信号传递时间。我们需要从源节点 K 开始,计算其他所有节点接收到信号的时间。信号从源节点传递到其他节点的时间由边的权重给定。如果有任何一个节点无法接收到信号,返回 -1。
题解
我们将采用 Bellman-Ford 算法来解决此问题,具体步骤如下:
- 初始化:将源节点到源节点的距离设为 0,其他节点到源节点的距离设为无穷大。
- 松弛操作:对每一条边进行 n-1 次松弛操作,以确保所有最短路径都能够正确更新。
- 判断节点是否可达:如果有节点的最短距离仍然是无穷大,表示该节点不可达,返回 -1
| 1 | package main |