📜  约翰逊的全对最短路径算法(1)

📅  最后修改于: 2023-12-03 14:56:49.599000             🧑  作者: Mango

约翰逊的全对最短路径算法

约翰逊的全对最短路径算法是一种用于找到图中所有顶点之间的最短路径的算法。它包括两个部分:预处理和所有对最短路径计算。

预处理

算法首先通过添加一个超级源节点,向图中添加一条权值为0的边连接所有节点。然后,使用Bellman-Ford算法计算该图中所有节点到超级源节点的最短路径。如果存在负权环,算法将停止,并且图中不存在最短路径。

去除超级源节点和它所连接的边,对于每个节点u,算法使用Dijkstra算法计算新的距离数组h(u),其中对于所有的v,d(u,v) = h(u) + c(u,v),c(u,v)表示从u到v的边的权值。这样,算法预处理完成后,就可以用h(u)计算任意两个节点之间的距离。

预处理的时间复杂度是O(nmlogn),其中n是节点数,m是边数。这里使用了Bellman-Ford和Dijkstra算法。

所有对最短路径计算

对于每对节点u和v,算法计算最短路径d(u,v) = h(u) + c(u,v) + h(v)。这里,h(u)和h(v)是预处理步骤中计算出的节点u和v的距离。虽然看起来需要重新计算所有的路径,但是,通过使用堆优化的Dijkstra算法,可以减少计算的重复量。

所有对最短路径计算的时间复杂度是O(nmlogn)。尽管这与单源最短路径算法的时间复杂度相同,但需要注意的是,对于每个查询,算法只需要执行Dijkstra算法一次,而不是像单源最短路径算法那样对每个节点分别执行一次。

实现

下面是使用Python实现约翰逊的全对最短路径算法的代码片段。这里的实现使用了堆优化的Dijkstra算法。

import heapq

def dijkstra(graph, starting_vertex):
    distances = {vertex: float('infinity') for vertex in graph}
    distances[starting_vertex] = 0
    pq = [(0, starting_vertex)]
    while len(pq) > 0:
        current_distance, current_vertex = heapq.heappop(pq)
        if current_distance > distances[current_vertex]:
            continue
        for neighbor, weight in graph[current_vertex].items():
            distance = current_distance + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(pq, (distance, neighbor))
    return distances

def johnson(graph):
    n = len(graph)
    # Add a super source vertex and edges with weight 0 to all vertices
    supergraph = {n+1: {v: 0 for v in graph}}
    supergraph.update(graph)
    # Run Bellman-Ford algorithm to get minimum distances from the super source vertex to all vertices
    h = dijkstra(supergraph, n+1)
    # Calculate new edge weights using minimum distances from the super source vertex
    for vertex in graph:
        for neighbor, weight in graph[vertex].items():
            graph[vertex][neighbor] = weight + h[vertex] - h[neighbor]
    # Compute all pairs shortest path using Dijkstra's algorithm
    distances = {}
    for vertex in graph:
        distances[vertex] = dijkstra(graph, vertex)
        # Add h(u) - h(v) to each computed distance to get the actual shortest path
        distances[vertex] = {k: v + h[vertex] - h[k] for k, v in distances[vertex].items()}
    return distances
结论

约翰逊的全对最短路径算法是一种实用的算法,它可以在较短的时间内计算所有节点对之间的最短距离。预处理步骤的时间复杂度为O(nmlogn),所有对最短路径计算的时间复杂度也为O(nmlogn)。尽管这与单源最短路径算法的时间复杂度相同,但是,约翰逊算法只需要执行Dijkstra算法一次,而不是像单源最短路径算法那样对每个节点分别执行一次,因此可以更快地计算出所有节点对之间的最短距离。