我有一个DAG(有向无环图),它由边列表表示,例如
edges = [('a','b'),('a','c'),('b','d')]
会给出图表
a - > b -> d
|
v
c
我正在做很多操作,我必须检查两个节点是否在同一条路径上(b
和d
在同一条路径上,而b
和{{1}不是来自上面的例子)这反过来正在减慢我的程序。我希望我能以某种方式遍历图形并保存所有路径,以便我可以在恒定时间内检查它。
这种加速是否可行?我将如何在python中实现这一点?
编辑:
请注意,我需要检查两个方向,因此,如果我有一对节点c
,我需要检查(a,b)
到a
和b
到{{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