两个节点之间的路径

发布于 2024-08-28 09:41:51 字数 256 浏览 5 评论 0原文

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

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

UPD2:我需要类似 find_all_paths() 函数的东西,如下所述:python.org/doc/essays/graphs.html 但是这个函数不能很好地处理大量节点和边缘 =(

I'm using networkx to work with graphs. I have pretty large graph (it's near 200 nodes in it) and I try to find all possible paths between two nodes. But, as I understand, networkx can find only shortest path. How can I get not just shortest path, but all possible paths?

UPD: path can contain each node only once.

UPD2: I need something like find_all_paths() function, described here: python.org/doc/essays/graphs.html But this function doesn't work well with large number of nodes and edged =(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你与清晨阳光 2024-09-04 09:41:51

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 的结果限制为给定端vertex as well:

>>> 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.5.3 中工作在 igraph 0.6 中。

igraph, another graph module for Python can calculate all the shortest paths between a given pair of nodes. Calculating all the paths does not make sense as you have infinitely many such paths.

An example for calculating all the shortest paths from vertex 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...]

If you have igraph 0.6 or later (this is the development version at the time of writing), you can restrict the result of get_all_shortest_paths to a given end vertex as well:

>>> 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]]

Of course you have to be careful; for instance, assume that you have a 100 x 100 grid graph (that can easily be generated by Graph.Lattice([100, 100], circular=False) in igraph). The number of shortest paths leading from the top left node to the bottom right node equals the number of possibilities to choose 100 elements out of 200 (proof: the length of the shortest path there has 200 edges, 100 of which will go "horizontally" in the grid and 100 of which will go "vertically"). This probably does not fit into your memory, therefore even calculating all the shortest paths between these two nodes is not really feasible here.

If you really need all the paths between two nodes, you can rewrite the function given on the webpage you mentioned using igraph, which will probably be faster than a pure Python solution as igraph's core is implemented in 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

It can be optimized more by converting the graph to an adjacency list representation first as it would spare repeated calls to 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, [])

Edit: fixed first example to work in igraph 0.5.3 as well, not only in igraph 0.6.

七婞 2024-09-04 09:41:51

这个实际上可以与 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

This one actually works with networkx, and it's non-recursive, which may be nice for large graphs.

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
只是一片海 2024-09-04 09:41:51

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

Dijkstra's algorithm will find the shortest path in a manner similar to a breadth first search (it substitutes a priority queue weighted by depth into the graph for the naive queue of a BFS). You could fairly trivially extend it to produce the 'N' shortest paths if you need some number of alternatives, although if you need the paths to be substantially different (e.g. scheduling the routes of security vans) you might need to be more clever about selecting paths that are significantly different from each other.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文