【问题标题】:Get list of parallel paths in a directed graph获取有向图中的并行路径列表
【发布时间】:2016-10-04 16:11:47
【问题描述】:

我需要一种算法来在有向图中查找所有并行路径的集合。这是我用于测试的示例的可视化表示。

这是我在 Python 中使用 networkx 的示例代码:

import networkx as nx

G = nx.MultiDiGraph()
# relevant part of graph to my question
G.add_edges_from([(1,2),(2,3),(3,4),(2,5),(5,6),(6,4),(4,7)])
# subordinate part of graph to my question
G.add_edges_from([(7,8),(8,9),(7,10),(10,11),(11,13),(11,12),(12,14)])

pp = get_parallel_paths(G)  # -> the function I'm looking for

# pp should contain:
# pp = [[[(2,3),(3,4)],[(2,5),(5,6),(6,4)]],[...]]
# the procedure should list all sets of parallel paths
# hence the [...] indicates a possible other set of parallel paths (not in example)

这是我正在寻找的函数“get_parallel_paths”。它不必在 Python 中:非常欢迎任何可以帮助我实现的算法的指针。

【问题讨论】:

  • 我已经改变了我的问题:这是我正在寻找的平行路径(每个连续的一个或多个边)。
  • 进一步澄清:如果在您的示例中,914 是同一个顶点,那么 [7,10,11,12,9][7,8,9] 是否会被视为“平行”?也就是说,分支会中断您的并行定义吗?
  • @Kittsil 考虑不可能有分支,因此如果 9 和 14 是同一个节点,那么您提到的路径不被视为并行路径。顺便说一句:学科是电力网络,并添加并行路径以增加网络部分的电力容量。分支不应该发生在这些并行路径上。
  • “平行”这个词在这里有什么意思吗,还是你只是在寻找两个顶点之间的路径集?
  • @Kundor 我不使用数学意义上的“并行”,如果那是你所指的。事实上,我使用像here 这样的“平行”,但我的案例没有边缘,而是有路径(边缘的连续性)。

标签: python algorithm networkx directed-graph


【解决方案1】:

有一个内置函数可以列出两个顶点之间的所有简单路径。这使用它来列出任意两个顶点之间的所有路径集:

def get_parallel_paths(G):
    return [list(nx.all_simple_paths(G, i, j)) for i in G.nodes_iter() for j in G.nodes_iter() if i != j and nx.has_path(G, i, j)]

要过滤掉任何内部顶点度数大于 2 的路径,我们可以这样做:

def get_parallel_paths(G):
    colpaths = []
    for i in G.nodes_iter():
        for j in G.nodes_iter():
            if i == j:
                continue
            nbp = nobranchpaths(G, i, j)
            if len(nbp) > 1:
                colpaths += [nbp]
    return colpaths

def nobranchpaths(G, u, v):
    paths = []
    for p in nx.all_simple_paths(G, u, v):
        if len(p) == 2 or max(G.degree(i) for i in p[1:-1]) == 2:
            paths += [p]
    return paths

这仅包括存在多个路径的顶点对;要包含具有唯一路径的对,请将 if len(nbp) > 1: 更改为 if len(nbp):

【讨论】:

  • 这确实可能是解决方案的一部分。就像 Kittsil 在他在原始问题的最后评论中所写的那样:我将不得不过滤输出以仅包含两个顶点之间的不同分支的路径(示例中为 2 和 4)。我也会调查的。
  • 要获取两个给定顶点之间的路径,请使用nx.all_simple_paths(G, 2, 4)。为了强制所有内部顶点都具有二度,如果这是你想要的,我认为你需要一种像 Kittsil 的方法;没有内置函数有这样的约束。
  • @theej 或者现在我想到了,它很容易过滤掉任何带有内部分支顶点的路径。我更新了我的答案。
  • 你成功了。非常感谢。
【解决方案2】:

如果考虑具有分支的并行路径,那么这个问题将是 NP 完全的(请参阅 vertex-disjoint paths problem)。

但是,由于没有考虑分支,所以问题很简单:

  1. 循环遍历所有顶点。
  2. 如果一个顶点有多个出边,请跟随它们直到它们收敛。
  3. 如果它们收敛到同一个节点,它们就是平行路径。

伪代码:

allParallelPaths = []

#loop over all vertices to find ones that split
foreach(vertices as v)
  if(out-degree(v) > 1) 

    #store every eventual target and the paths that got there
    destinations = new Map()
    foreach(v.out as e)
      path = [e]

      #stop at any vertex that has non-one in- or out-degree
      while(in-degree(e.target) == 1 && out-degree(e.target) == 1)
        e = e.target.out[0]
        path.push(e)

      #make a list of paths that reached the destination
      if(empty(destinations[e.target]))
        destinations[e.target] = []
      destinations[e.target].push(path)

    foreach(destinations as dest)
      if(dest.size > 1)
        allParallelPaths.push(dest)

【讨论】:

  • 感谢您的详尽回答。我理解你的做法。我将尝试实现这一点,如果它符合我的要求,我会将您的答案标记为解决方案。
  • @Kundor:当然,我知道演习。我对堆栈交换并不陌生,但对于堆栈溢出来说太新了,以至于我的赞成票无法被看到。我非常感谢你们俩的合作!验收正在进行中。
  • 虽然这个算法可以解决我的问题,但我认为@Kundor 给出的解决方案更好。
  • @theej Kundor's 当然更干净,并且避免了假设。在某些情况下,这会更快;如前所述,他可能会占用 O(2^n),而这保证会在 O(n^2) 中运行。如果时间过长,请记住这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
相关资源
最近更新 更多