📜  DAA |约翰逊算法(1)

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

DAA | 约翰逊算法

介绍

DAA算法也称为约翰逊算法是一种基于Dijkstra算法优化了负权边的最短路径算法。它是由Neil D. Jones和Cristopher M. Fredriksen发明的。与Dijkstra算法相比,它具有更快的时间复杂度,可以更有效地处理负权边的情况,并且可以解决保真的有向图及其变种。

算法步骤
  1. 添加一个新的源节点,将其连接到图中的所有节点,并将其权值设置为0 。
  2. 使用SPFA算法(Shortest Path Faster Algorithm)计算源节点到每个节点的最短距离。
  3. 从图中删除源节点,并将其作为最小权重估计,每个节点的权值都减去源节点的权值。
  4. 使用再次使用SPFA算法计算每个节点的最短路径。
  5. 对每个节点的最短路径进行优化,得到其实际权重。
性能
  • 时间复杂度:$O(E\times logN)$ ,其中 $E$ 为图中边的数量, $N$ 为图中节点的数量。
  • 空间复杂度:$O(N+E)$ ,其中 $N$ 为图中节点的数量, $E$ 为图中边的数量。
代码示例

以下是Python实现的DAA算法示例代码:

from queue import Queue
from typing import List, Tuple

def daa(graph: List[List[Tuple[int, int]]]) -> List[int]:
    def spfa(source: int) -> List[int]:
        distance = [float('inf')] * (n + 1)
        inqueue = [False] * (n + 1)
        q = Queue()
        distance[source] = 0
        inqueue[source] = True
        q.put(source)
        while not q.empty():
            u = q.get()
            inqueue[u] = False
            for v, w in graph[u]:
                if distance[v] > distance[u] + w:
                    distance[v] = distance[u] + w
                    if not inqueue[v]:
                        q.put(v)
                        inqueue[v] = True
        return distance
    
    n = len(graph) - 1
    # Step 1
    graph.append([(i, 0) for i in range(1, n + 1)])
    # Step 2
    distance_s = spfa(n + 1)
    if distance_s[n + 1] < 0:  # 有负环
        return None
    # Step 3
    h = distance_s[n + 1]
    for i in range(1, n + 1):
        graph[i].append((n + 1, h - distance_s[i]))
    # Step 4
    distance_i = spfa(n + 1)
    # Step 5
    result = [0] * n
    for i in range(1, n + 1):
        result[i - 1] = distance_i[i] + distance_s[i] - h
    return result

代码片段开头使用了队列Queue,需要先导入Queue类。

在主函数daa中先进行了Step 1,Step 2,Step 3三步,得到了优化后的图结构以及源节点到各节点的相对权值。然后进行Step 4,再次用SPFA算法计算每个节点的最短路径。最后Step 5,对每个节点的最短路径进行优化,得到其实际权重。

参考文献