Belloman-Ford算法

文章介绍了在图论中解决含有负权重边的单源最短路径问题的两种算法:Bellman-Ford和SPFA。Bellman-Ford能处理负边并检测负环,但复杂度为O(VE),而SPFA是其优化,减少了不必要的松弛操作,但在最坏情况下仍可能达到O(VE)的复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法介绍

Dijkstra可以解决单源无负边最短路径问题。但是当遇到含有负边的单源最短路径问题就需要使用Bellman-Ford算法来解决。Bellman-Ford算法还可以检测出负环。

算法步骤

源点s,数组 d [ u ] d[u] d[u]表示s到u的最短距离

初始化: d [ s ] = 0 d[s]=0 d[s]=0, ∀ v ∈ V − { s } , d [ v ] = ∞ \forall v \in V-\{s\},d[v]=\infin ∀v∈V−{s},d[v]=∞

循环 ∣ V ∣ − 1 |V|-1 ∣V∣−1次,每次对每条边进行松弛操作:对于有向边 ( u , v ) (u,v) (u,v),如果 d [ u ] + w [ u , v ] < d [ v ] d[u]+w[u,v]<d[v] d[u]+w[u,v]<d[v],则 d [ v ] = d [ u ] + w [ u , v ] d[v]=d[u]+w[u,v] d[v]=d[u]+w[u,v]

对每条边进行松弛操作,如果操作成功,说明有负环。否则最后的 d [ i ] d[i] d[i]就是源点s到i的最短路径长度

我们可以看到Bellman-Ford算法的算法结构是比较简单的,复杂度是 O ( V E ) O(VE) O(VE),比Dijkstra算法最好为 O ( E + V l o g V ) O(E+VlogV) O(E+VlogV)大,但是可以处理负边。

正确性证明

可以看到算法的核心操作就是松弛。这就要用到另一篇博客中介绍Dijkstra算法的时候的几个关于松弛操作的引理,这里就不再进行证明,如果想要看证明可以移步:传送门。

设源点为s,d[u]表示源点到u的最短路径,w[u,v]表示从点u到点v的一条有向边的长度, δ ( u , v ) \delta(u,v) δ(u,v)表示u到v的最短路径。

最优子结构:任意两点之间的最短路径的子路径仍然是最短路径

引理1:初始化以后 ∀ v ∈ V , d [ u ] ⩾ δ ( s , v ) \forall v \in V,d[u]\geqslant\delta(s,v) ∀v∈V,d[u]⩾δ(s,v)

引理2:假设存在s到v的最短路径:s->…->u->v, d [ u ] = δ ( s , u ) d[u]=\delta(s,u) d[u]=δ(s,u),那么在对边(u,v)进行松弛操作以后 d [ v ] = δ ( s , v ) d[v]=\delta(s,v) d[v]=δ(s,v)

假设没有负边环,那么:

对于初始情况, d [ s ] = 0 = δ ( s , s ) d[s]=0=\delta(s,s) d[s]=0=δ(s,s)

因为如果 d [ s ] < 0 d[s]<0 d[s]<0说明存在一个环s->…->s的权值和为负,而假设没有负边环,所以不存在这样的情况

假设对于最短路径经过边数为k的点u在第k次循环 d [ u ] = δ ( s , u ) d[u]=\delta(s,u) d[u]=δ(s,u),那么由引理2,所有最短路径经过边数为k+1的点v在第k+1次循环后, d [ v ] = δ ( s , v ) d[v]=\delta(s,v) d[v]=δ(s,v)

因为一个节点数目为 ∣ V ∣ |V| ∣V∣的图的简单路径最长为 ∣ V ∣ − 1 |V|-1 ∣V∣−1,所以 ∣ V ∣ − 1 |V|-1 ∣V∣−1次循环以后 ∀ v ∈ V , d [ v ] = δ ( s , v ) \forall v \in V,d[v]=\delta(s,v) ∀v∈V,d[v]=δ(s,v)

第|V|次循环应该无法进行松弛操作。

如果第|V|次循环可以进行松弛操作,则由逆反命题,说明有负边环。

证毕。

SPFA算法

算法介绍

SPFA算法是对Bellman-Ford算法的优化。因为Bellman-Ford算法中会对已经确定最短路径的点进行松弛判断,但这实际上是不必要的。我们需要松弛的是被松弛的点可以到达的点。正是这种思想我们有了SPFA算法。

算法步骤

源点s,数组 d [ u ] d[u] d[u]表示s到u的最短距离,队列Q表示需要操作进行松弛操作的点的集合

初始化: d [ s ] = 0 , ∀ v ∈ V − { s } , d [ v ] = ∞ d[s]=0,\forall v \in V-\{s\},d[v]=\infin d[s]=0,∀v∈V−{s},d[v]=∞,将点s加入Q中

从Q中取出一个点,对它可以到达的点进行松弛操作,并将成功进行松弛操作的点加入Q中

重复上述步骤直到Q为空

如果某个点被松弛了|V|次,说明有负边环

正确性证明

同Bellman-Ford算法,可以用归纳法进行证明。本质上SPFA算法提取出了Bellman-Ford算法中有效的操作。

复杂度分析

可以构造图使得算法复杂度为 O ( V E ) O(VE) O(VE),因此算法的最坏复杂度为 O ( V E ) O(VE) O(VE)。虽然SPFA算法是Bellman-Ford算法的优化,但是对于一些特殊的图可能因为有判断操作和出队入队操作导致两者复杂度相近。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值