给定一个非循环有向图,返回“同一级别”的节点集合的集合?

Nim*_*Nim 4 python algorithm graph-theory graph networkx

首先,我不确定这样的算法叫什么,这是主要问题 - 所以问题的第一部分是这个算法叫什么?

基本上我有一个DiGraph()插入节点[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]和边缘的([1,3],[2,3],[3,5],[4,5],[5,7],[6,7],[7,8],[7,9],[7,10])

由此我想知道是否有可能获得如下集合:[[1, 2, 4, 6], [3], [5], [7], [8, 9, 10]]

编辑:如果有帮助的话,让我添加一些限制。- 没有循环,这是有保证的 - 图表没有一个起点

我想做的是收集同一级别的节点,以便它们的处理可以并行化,但在外部集合中,处理是串行的。

编辑2:很明显,我没有充分考虑这一点,因此描述“级别”的最简单方法是最深的前驱,即具有相同前驱深度的所有节点。因此,上面列表中的第一个条目都是最深前驱为 0 的节点,第二个条目为 1,第三个条目为 2,依此类推。在每个列表中,同级的顺序无关紧要,因为它们将被并行处理。

Ami*_*ory 5

您的问题表明您希望该图的输出为[[1, 2, 4, 6], [3], [5], [7], [8, 9, 10]]。IIUC,模式如下:

  • [1, 2, 4, 6]是没有边的节点。

  • [3]是没有边的节点,假设所有先前的节点都被删除。

  • [4]是没有边的节点,假设所有先前的节点都被删除。

  • 等等(直到所有节点都被擦除)

假设我们从

g = networkx.DiGraph()
g.add_edges_from([[1,3],[2,3],[3,5],[4,5],[5,7],[6,7],[7,8],[7,9],[7,10]])
Run Code Online (Sandbox Code Playgroud)

然后我们可以将其编码为

def find_levels(g):
    levels = []
    while g.nodes():
        no_in_nodes = [n for (n, d) in g.in_degree(g.nodes()).items() if d == 0]
        levels.append(no_in_nodes)
        for n in no_in_nodes:
            g.remove_node(n)
    return levels
Run Code Online (Sandbox Code Playgroud)

如果我们运行这个,我们会得到结果:

>>> find_levels(g)
[[1, 2, 4, 6], [3], [5], [7], [8, 9, 10]]
Run Code Online (Sandbox Code Playgroud)

这里的复杂度是θ(|V| 2 + |E|)可以使用斐波那契堆构建稍微复杂的版本。基本上,所有顶点都需要放入堆中,每个级别由度数为 0 的顶点组成。每次弹出一个顶点,并且删除其他顶点的边时,我们可以将其转换为堆减少键操作(减少剩余顶点的入度)。这会将运行时间减少到θ(|V| log(|V|) + |E|)