【问题标题】:Path between two nodes两个节点之间的路径
【发布时间】:2014-02-19 20:08:25
【问题描述】:

我正在使用 networkx 来处理图表。我有相当大的图表(其中有近 200 个节点),我尝试找到两个节点之间的所有可能路径。但是,据我了解,networkx 只能找到最短路径。我怎样才能不仅得到最短路径,而且得到所有可能的路径?

UPD:路径只能包含每个节点一次。

UPD2:我需要类似 find_all_paths() 函数,在此处描述:python.org/doc/essays/graphs.html 但此函数不适用于大量节点和边缘 =(

【问题讨论】:

  • 一般是做不到的。如果您的图中有循环,则路径的数量是无限的,例如。 A->B->A->B->...->B->C 您需要为您的问题添加更多限制条件(例如,没有周期,或者您计划如何处理周期)。
  • 虽然您可以使用龟兔算法检测路径中的循环。通过将其与广度优先搜索相结合,您可能会得到一个可以接受的近似值,尽管我敢说它会有些低效。
  • 我需要 find_all_paths() 之类的函数,如下所述:python.org/doc/essays/graphs.html 但此函数不适用于大量节点和边缘 =(
  • @user285070 的链接已损坏,但我无法编辑评论,因此更正的评论在这里:python.org/doc/essays/graphs。如果你更喜欢 Wayback 缓存:wayback.archive.org/web/20131102032815/http://www.python.org/…

标签: python networkx igraph


【解决方案1】:

igraph,另一个 Python 图形模块可以计算给定节点对之间的所有 最短 路径。计算所有路径没有意义,因为您有无数这样的路径。

计算从顶点 0 开始的所有最短路径的示例:

>>> from igraph import Graph
>>> g = Graph.Lattice([10, 10], circular=False)
>>> g.get_all_shortest_paths(0)
[...a list of 3669 shortest paths starting from vertex 0...]

如果您有 igraph 0.6 或更高版本(这是撰写本文时的开发版本),您也可以将 get_all_shortest_paths 的结果限制为给定的结束顶点:

>>> g.get_all_shortest_paths(0, 15)
[[0, 1, 2, 3, 4, 14, 15],
 [0, 1, 2, 12, 13, 14, 15],
 [0, 10, 11, 12, 13, 14, 15],
 [0, 1, 11, 12, 13, 14, 15],
 [0, 1, 2, 3, 13, 14, 15],
 [0, 1, 2, 3, 4, 5, 15]]

当然要小心;例如,假设您有一个 100 x 100 的网格图(可以通过 igraph 中的Graph.Lattice([100, 100], circular=False) 轻松生成)。从左上角节点到右下角节点的最短路径的数量等于从 200 个元素中选择 100 个元素的可能性的数量(证明:最短路径的长度有 200 条边,其中 100 条将“水平”在网格中,其中 100 个将“垂直”移动)。这可能不适合您的记忆,因此即使计算这两个节点之间的所有 最短 路径在这里也不可行。

如果你真的需要两个节点之间的所有路径,你可以使用igraph重写你提到的网页上给出的函数,这可能会比纯Python解决方案更快,因为igraph的核心是用C实现的:

def find_all_paths(graph, start, end, path=[]):
    path = path + [start]
    if start == end:
        return [path]
    paths = []
    for node in set(graph.neighbors(start)) - set(path):
        paths.extend(find_all_paths(graph, node, end, path))
    return paths

可以通过首先将图形转换为邻接表表示来对其进行更多优化,因为它可以避免重复调用graph.neighbors

def find_all_paths(graph, start, end):
    def find_all_paths_aux(adjlist, start, end, path):
        path = path + [start]
        if start == end:
            return [path]
        paths = []
        for node in adjlist[start] - set(path):
            paths.extend(find_all_paths_aux(adjlist, node, end, path))
        return paths

    adjlist = [set(graph.neighbors(node)) for node in xrange(graph.vcount())]
    return find_all_paths_aux(adjlist, start, end, [])

编辑:修复了第一个示例以在 igraph 0.5.3 中工作,而不仅仅是在 igraph 0.6 中。

【讨论】:

  • 首先,感谢您提供这么棒的帖子!但是我的代码有一些问题。我已经下载并安装了 igraph - 适用于 Windows 的 Python 扩展模块。然后我尝试运行您的第一个示例(g.get_all_shortest_paths),但它返回错误 igraph.core.InternalError: Error at .\src\structural_properties.c:1032: Invalid mode argument, Invalid mode 你能解释一下如何解决它?
  • 是的,你是对的——第一个代码示例仅适用于 igraph 0.6(这是 igraph 的开发分支)。在 igraph 0.5.3 中,get_all_shortest_paths 仅接受单个源顶点 ID,它为您提供从该节点到网络中所有其他节点的所有最短路径。因此,如果您这样做,代码将起作用: g.get_all_shortest_paths(0) 这将为您提供从零开始的 3669 条不同路径的列表;它们都是网络中源自顶点 0 的最短路径。
【解决方案2】:

这个实际上适用于networkx,它是非递归的,这对于大型图可能很好。

def find_all_paths(graph, start, end):
    path  = []
    paths = []
    queue = [(start, end, path)]
    while queue:
        start, end, path = queue.pop()
        print 'PATH', path

        path = path + [start]
        if start == end:
            paths.append(path)
        for node in set(graph[start]).difference(path):
            queue.append((node, end, path))
    return paths

【讨论】:

  • 这段代码是否计算了任意两个节点之间的所有可能路径?包括最短路径和最长路径?
【解决方案3】:

Dijkstra 的算法将以类似于广度优先搜索的方式找到最短路径(它将按深度加权的优先级队列替换为 BFS 的朴素队列)。如果您需要一些替代方案,您可以相当简单地扩展它以产生“N”条最短路径,但如果您需要路径大不相同(例如安排安全货车的路线),您可能需要更聪明地选择彼此有很大不同的路径。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 2016-03-04
    • 2012-05-21
    • 2010-10-17
    • 1970-01-01
    • 2023-01-15
    相关资源
    最近更新 更多