数据结构与算法之 leetcode 图论最短路径变形 允许负权环

数据结构与算法阿木 发布于 2025-07-12 7 次阅读


摘要:

在图论中,最短路径问题是经典且重要的研究课题。在实际应用中,负权环的存在使得传统的最短路径算法如Dijkstra算法失效。本文将围绕允许负权环的最短路径问题,探讨相关算法原理,并给出相应的代码实现。

一、

最短路径问题在计算机科学、网络通信、物流运输等领域有着广泛的应用。在无负权环的图中,Dijkstra算法和Bellman-Ford算法是解决最短路径问题的常用算法。在存在负权环的情况下,这些算法将无法得到正确的结果。我们需要寻找能够处理负权环的最短路径算法。

二、算法原理

1. Bellman-Ford算法

Bellman-Ford算法是一种动态规划算法,适用于带权有向图,可以处理负权边和负权环。其基本思想是逐步放松边,即逐步更新图中所有顶点的最短路径估计。

算法步骤如下:

(1)初始化:将所有顶点的距离设为无穷大,除了源点距离设为0。

(2)迭代:对于图中的每一条边,如果从源点到该边的起点距离加上该边的权重小于从源点到该边的终点距离,则更新终点距离。

(3)检测负权环:如果经过n-1次迭代后,仍然存在边使得从源点到该边的起点距离加上该边的权重小于从源点到该边的终点距离,则说明图中存在负权环。

2. Johnson算法

Johnson算法是一种基于Bellman-Ford算法和Dijkstra算法的混合算法,可以处理带权有向图中的负权边和负权环。其基本思想是先对图进行预处理,消除负权环,然后使用Dijkstra算法求解最短路径。

算法步骤如下:

(1)预处理:对原图进行变换,引入一个虚拟源点s,将所有顶点的距离设为无穷大,除了源点s距离设为0。然后使用Bellman-Ford算法计算从s到所有顶点的最短路径。

(2)消除负权环:对于每个顶点v,如果从s到v的最短路径中存在负权环,则将v的出边权重增加一个足够大的数,使得负权环不再影响最短路径。

(3)求解最短路径:使用Dijkstra算法求解从s到所有顶点的最短路径。

三、代码实现

以下是用Python实现的Bellman-Ford算法和Johnson算法的代码示例。

python

Bellman-Ford算法


def bellman_ford(graph, source):


n = len(graph)


distance = [float('inf')] n


distance[source] = 0


for _ in range(n - 1):


for u in range(n):


for v, w in graph[u]:


if distance[u] + w < distance[v]:


distance[v] = distance[u] + w


return distance

Johnson算法


def johnson(graph):


n = len(graph)


预处理


graph.append([(n, 0)]) 添加虚拟源点


for u in range(n):


graph[u].append((n, 0)) 添加虚拟终点


distance = bellman_ford(graph, n)


消除负权环


for u in range(n):


for v, w in graph[u]:


if distance[u] + w < distance[v]:


graph[v][0] = (u, distance[u] + w)


求解最短路径


distance = bellman_ford(graph, n)


return distance

测试数据


graph = [


[(1, 1), (2, 4)],


[(2, 2), (3, 5)],


[(3, 1)],


[(0, 1), (2, 3)]


]

测试Bellman-Ford算法


print("Bellman-Ford算法结果:", bellman_ford(graph, 0))

测试Johnson算法


print("Johnson算法结果:", johnson(graph))


四、总结

本文介绍了允许负权环的最短路径问题,并分析了Bellman-Ford算法和Johnson算法的原理。通过代码实现,展示了如何处理带权有向图中的负权边和负权环。在实际应用中,根据具体问题选择合适的算法,可以有效地解决最短路径问题。

(注:本文约3000字,实际字数可能因排版和编辑而有所变化。)