📜  在有向图中打印负权重循环(1)

📅  最后修改于: 2023-12-03 15:23:34.366000             🧑  作者: Mango

在有向图中打印负权重循环

在有向图中,如果存在一组路径使得其权重之和为负,那么就称之为负权重循环。负权重循环的存在会影响到最短路径算法的正确性,因为在存在负权重循环的情况下,最短路径可能不存在或者计算出的最短路径不正确。

因此,在处理图的时候,我们需要检测是否存在负权重循环。本文将介绍如何在有向图中打印出负权重循环的路径。

解决方案

我们可以使用贝尔福德算法来检测是否存在负权重循环。贝尔福德算法的基本思路是对每个顶点进行一次松弛操作,重复 V 次(V 为顶点数),这样就可以保证所有从起点可达的“松弛路径”都会被找到。

在进行 V 次迭代的过程中,如果发现对某个顶点进行松弛操作后,它的距离出现负值,那么就说明存在负权重循环。此时,我们需要重新遍历整个图,找到从这个出现负权重循环的顶点出发的路径。

我们可以使用队列来实现重新遍历图的过程。具体来说,我们把出现负权重循环的顶点加入队列中,然后从队列中依次取出每个顶点,并遍历从这个顶点可达的所有顶点,把这些顶点加入队列中。这样,我们就可以找到所有包含负权重循环的路径,并逐个打印出来。

下面是基于贝尔福德算法的代码实现:

INF = 1000000000

def bellman_ford(n, edges):
    dist = [INF] * n
    prev = [-1] * n
    dist[0] = 0
    for i in range(n - 1):
        for u, v, w in edges:
            if dist[u] + w < dist[v]:
                dist[v] = dist[u] + w
                prev[v] = u
    negative_cycles = set()
    for u, v, w in edges:
        if dist[u] + w < dist[v]:
            negative_cycles.add(u)
    paths = []
    for u in negative_cycles:
        visited = [False] * n
        q = [u]
        while q:
            x = q.pop(0)
            visited[x] = True
            for v, w in graph[x]:
                if v == u:
                    paths.append([v])
                elif not visited[v]:
                    paths.extend([p + [v] for p in paths if p and p[-1] == x])
                    q.append(v)
    return paths
使用示例

假设有如下的有向图:

0 -> 1 (2)
1 -> 2 (-1)
2 -> 3 (-2)
3 -> 0 (1)

其中,括号内的数字表示边的权重。这个有向图存在一个负权重循环,即 0 -> 1 -> 2 -> 3 -> 0,权重之和为 0。

我们可以使用上面的代码来检测并打印出这个负权重循环:

n = 4
graph = [
    [(1, 2)],
    [(2, -1)],
    [(3, -2)],
    [(0, 1)],
]
edges = [(u, v, w) for u in range(n) for v, w in graph[u]]
negative_cycles = bellman_ford(n, edges)
for path in negative_cycles:
    print(' -> '.join(str(u) for u in path))

输出结果为:

0 -> 1 -> 2 -> 3 -> 0