📅  最后修改于: 2023-12-03 14:51:28.339000             🧑  作者: Mango
在一个无向图中,找出从源节点到目标节点的所有最短路径是一个常见的问题。下面以 Python 语言为例介绍如何实现。
通常我们可以使用广度优先搜索(BFS)来找到最短路径。具体来说,我们从源节点开始进行 BFS,记录每个节点到源节点的距离和前驱节点。
当我们遇到目标节点时,可以通过回溯前驱节点的信息,找到源节点到目标节点的一条最短路径。但这样只能找到一条路径,如何找到所有最短路径呢?
可以使用深度优先搜索(DFS)来枚举所有的路径。具体来说,我们从目标节点开始进行 DFS,以距离为准限制搜索深度,每次遍历到一个节点时,如果这个节点到源节点的距离比目标节点到源节点的距离小,那么可以继续向前搜索。如果遇到源节点,那么就找到了一条最短路径。
但是这样会重复枚举一些路径,如何去重呢?可以记录每个节点的后继节点,当我们访问一个节点时,只有从它的后继节点继续向前搜索才能得到一条新的路径。
下面是一个 Python 实现,假设输入的图是通过一个邻接矩阵表示的,其中 graph[i][j]
表示节点 i
和节点 j
之间是否存在一条边,距离都为 1。源节点和目标节点分别为 src
和 dst
。
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]
代表两条最短路径。