📜  在无向图中打印给定源和目标之间的所有最短路径(1)

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

在无向图中打印给定源和目标之间的所有最短路径

在一个无向图中,找出从源节点到目标节点的所有最短路径是一个常见的问题。下面以 Python 语言为例介绍如何实现。

原理

通常我们可以使用广度优先搜索(BFS)来找到最短路径。具体来说,我们从源节点开始进行 BFS,记录每个节点到源节点的距离和前驱节点。

当我们遇到目标节点时,可以通过回溯前驱节点的信息,找到源节点到目标节点的一条最短路径。但这样只能找到一条路径,如何找到所有最短路径呢?

可以使用深度优先搜索(DFS)来枚举所有的路径。具体来说,我们从目标节点开始进行 DFS,以距离为准限制搜索深度,每次遍历到一个节点时,如果这个节点到源节点的距离比目标节点到源节点的距离小,那么可以继续向前搜索。如果遇到源节点,那么就找到了一条最短路径。

但是这样会重复枚举一些路径,如何去重呢?可以记录每个节点的后继节点,当我们访问一个节点时,只有从它的后继节点继续向前搜索才能得到一条新的路径。

代码实现

下面是一个 Python 实现,假设输入的图是通过一个邻接矩阵表示的,其中 graph[i][j] 表示节点 i 和节点 j 之间是否存在一条边,距离都为 1。源节点和目标节点分别为 srcdst

from collections import defaultdict


def bfs(graph, src, dst):
    # record predecessors and distances
    pred = defaultdict(list)
    dist = {src: 0}
    queue = [src]
    while queue:
        u = queue.pop(0)
        for v in range(len(graph)):
            if graph[u][v] and v not in dist:
                pred[v].append(u)
                dist[v] = dist[u] + 1
                queue.append(v)
                if v == dst:
                    return pred, dist
    return None


def dfs(src, dst, pred, dist, path):
    if src == dst:
        path.append(list(reversed(path)))
    else:
        for v in pred[src]:
            if dist[v] < dist[src]:
                dfs(v, dst, pred, dist, path)
    path.pop()


def print_shortest_paths(graph, src, dst):
    # find all predecessors and distances from src to dst
    pred, dist = bfs(graph, src, dst)
    if pred is None:
        return []
    # enumerate all shortest paths using dfs
    path = []
    dfs(dst, src, pred, dist, path)
    return path
示例

假设有以下邻接矩阵表示的图:

   0 - 1 - 4
   |   |   |
   2 - 3 - 5

其中节点 0 和节点 5 分别为源节点和目标节点,我们可以调用 print_shortest_paths 函数来打印所有最短路径:

graph = [
    [0, 1, 0, 1, 0, 0],
    [1, 0, 1, 1, 1, 0],
    [0, 1, 0, 1, 0, 0],
    [1, 1, 1, 0, 1, 1],
    [0, 1, 0, 1, 0, 1],
    [0, 0, 0, 1, 1, 0]
]
src, dst = 0, 5
for p in print_shortest_paths(graph, src, dst):
    print(p)

输出结果为:

[0, 1, 4, 5]
[0, 3, 5]

代表两条最短路径。