检查两个节点是否在DAG的恒定时间内在同一路径上

时间:2016-10-12 07:32:51

标签: python algorithm graph-algorithm directed-acyclic-graphs graph-traversal

我有一个DAG(有向无环图),它由边列表表示,例如

edges = [('a','b'),('a','c'),('b','d')]

会给出图表

a - > b -> d
|
v
c

我正在做很多操作,我必须检查两个节点是否在同一条路径上(bd在同一条路径上,而b和{{1}不是来自上面的例子)这反过来正在减慢我的程序。我希望我能以某种方式遍历图形并保存所有路径,以便我可以在恒定时间内检查它。

这种加速是否可行?我将如何在python中实现这一点?

编辑: 请注意,我需要检查两个方向,因此,如果我有一对节点c,我需要检查(a,b)ab到{{1} }}

1 个答案:

答案 0 :(得分:3)

您确实想要找到图表的transitive closure

  

在计算机科学中,可以考虑传递闭包的概念   作为构建一个可以回答的数据结构   可达性问题。也就是说,可以从节点a到达节点d   一个或多个啤酒花?

有多种方法可以找到图的传递闭包。最简单的方法是使用floyd-warshall算法 O(| V | 3 。解释here

另一种方法是从每个节点执行DFS,并将您访问的所有节点标记为可从当前节点访问。解释here

还有一种方法仅适用于DAG。首先在DAG上执行拓扑排序。然后在拓扑排序列表中向后工作,并OR将当前节点的子节点的传递闭包在一起,以获得当前节点的传递闭包。解释here

以下是基于DFS的方法的Python实现:

def create_adj_dict_from_edges(edges):
    adj_dict = {}

    for e in edges:
        for u in e:
            if u not in adj_dict:
                adj_dict[u] = []

    for e in edges:
        adj_dict[e[0]].append(e[1])
    return adj_dict

def transitive_closure_from_adj_dict(adj_dict):

    def dfs(node, visited):
        if node not in adj_dict:
            return
        for next in adj_dict[node]:
            if next in visited:
                continue
            visited.add(next)
            dfs(next,visited)

    reachable = {}
    for node in adj_dict:
        visited = set(node,)
        dfs(node,visited)
        reachable[node] = visited

    return reachable

def main():
    edges = [('a','b'),('a','c'),('b','d')]
    adj_dict = create_adj_dict_from_edges(edges)
    tc = transitive_closure_from_adj_dict(adj_dict)
    print tc
    # is there a path from (b to d) or (d to b)
    print 'd' in tc['b'] or 'b' in tc['d']
    # is there a path from (b to c) or (c to b)
    print 'c' in tc['b'] or 'b' in tc['c']


if __name__ == "__main__":
    main()

<强>输出

{'a': set(['a', 'c', 'b', 'd']), 'c': set(['c']), 'b': set(['b', 'd']), 'd': set(['d'])}
True
False