列出所有可能的“最短”路径

2 投票
1 回答
621 浏览
提问于 2025-04-18 14:06

我遇到了一个组合问题,这个问题可以看作是一个网络搜索问题。为了更好地可视化并使用已经实现的功能,我决定使用networkx这个库(其实我没有足够的时间去用其他方式实现)。

我的问题比较复杂,但我会尽量从最简单的地方开始讲解,以便大家理解。总的来说,我需要找出到达树的终点节点的组合。

下面的图是一个简单的例子:

enter image description here


在这个例子中,BDFH是终点节点,而起点用O表示。所以,一个路径组合可能是:

OAB
OCD
OED
OEF
OH
OGH

不过,我实际上是想寻找到达终点节点的“最短”或“最优”路径。这个图(或者说边)并没有提供关于路径“成本”的任何信息。成本的评估将根据找到的组合结果来进行。评估这些组合的“实际”成本是计算上非常耗费资源的。虽然这个图提供的信息不多,但有一点是明确的:为了到达HOH始终比OGH更好。因此,组合OGH可以从可能的组合列表中排除。这本质上就像是距离的度量。

还有一点,实际上DF是等效的节点(它们是不同的节点,但在我的应用中意义相同)。这样的信息只有在两个节点

- see each other
- see exactly the same nodes

仔细观察图形,我们还可以发现CE也是等效节点。所以,更具体地说:组合OCDOED实际上是相同的。一旦OCD被添加到组合列表中,就不需要再添加OED。从图中也可以看出,由于DF是相同的,一旦OCD被添加到列表中,就不需要再添加OCF

总之,在这种情况下,解决方案是:

OAB
anyone of OCD, OED, OCF, OEF
OH

为了绘制这个图,我参考了networkx的教程,然后创建了下面的代码:

import networkx as nx
import matplotlib.pyplot as plt

graph = [('O', 'A'), ('O', 'C'),  ('O', 'E'),  ('O', 'G'),  ('O', 'H'),  
         ('A', 'B'), ('A', 'O'),
         ('B', 'A'),
         ('C', 'D'), ('C', 'E'), ('C', 'F'), ('C', 'O'),
         ('D', 'E'), ('D', 'C'), ('D', 'F'),  
         ('E', 'C'), ('E', 'D'), ('E', 'F'), ('E', 'O'),
         ('F', 'C'), ('F', 'D'), ('F', 'E'),
         ('G', 'H'), ('G', 'O'), 
         ('H', 'G'), ('H', 'O')]

G=nx.DiGraph()
for edge in graph:
    G.add_edge(edge[0], edge[1])

pos=nx.graphviz_layout(G,prog='dot')
nx.draw(G, pos)
plt.show()

所以,我的问题是希望能列出这样的序列,使用任何工具箱,但最好是networkx。第一步可能是简化(或减少)图形,然后再创建一个图对象。一旦得到了简化的图形,就可以使用nx.all_simple_path命令列出所有的替代路径。我需要你的帮助来进行这样的图形简化。

我的图形不深,通常和例子中的大小差不多。

1 个回答

1

我看过整个模块的手册,也尝试了不同的搜索算法,但就是找不到现成的实现方法,或者针对这种特定情况的解决办法。

所以,根据评论中得到的建议,我自己写了一个简化器,先把所有“多余”的节点去掉,然后再创建图。我是通过把列表转换成集合,然后比较它们是否相同来做到这一点的。之后,我创建了图,并使用 nx.all_simple_paths 命令列出了所有的解决方案。一旦得到了路径,这次我又检查了一下,看看是否有一些路径(比如 OGH),当去掉倒数第二个字母后,得到的路径(OH)是否也在 nx.all_simple_paths 的列表中。如果有的话,我就把这个解决方案去掉。

我写的脚本有点杂乱,也没有用到什么特别的技巧。所以,我决定写下这个解决方案的方法论。

撰写回答