我正在使用递归来查找从某个点A到某个点D的路径。 我正在横穿图表找到路径。
让我们说:
Graph = {'A':['route1','route2'],'B':['route1','route2','route3','route4'],'C':['route3' ,'route4'],'D':['route4']}
可通过以下方式访问:
A - > route1,route2
B - > route2,route 3,route 4
C - > route3,route4
此路径中有两种解决方案,从A - > d:
route1 - > route2 - >路径4
route1 - > route2 - > route3 - >路径4
由于B点和A点都有路径1和路径2.有一个无限循环,所以每当我添加一个检查 我访问节点(0或1值)。
然而,通过检查,我只得到一个解决方案:route1 - > route2 - > route4,而不是其他可能的解决方案。
以下是实际编码:路由将被Reactions取代。
def find_all_paths(graph,start, end, addReaction, passed = {}, reaction = [] ,path=[]):
passOver = passed
path = path + [start]
reaction = reaction + [addReaction]
if start == end:
return [reaction]
if not graph.has_key(start):
return []
paths=[]
reactions=[]
for x in range (len(graph[start])):
for y in range (len(graph)):
for z in range (len(graph.values()[y])):
if (graph[start][x] == graph.values()[y][z]):
if passOver.values()[y][z] < 161 :
passOver.values()[y][z] = passOver.values()[y][z] + 1
if (graph.keys()[y] not in path):
newpaths = find_all_paths(graph, (graph.keys()[y]), end, graph.values()[y][z], passOver , reaction, path)
for newpath in newpaths:
reactions.append(newpath)
return reactions
以下是方法调用:dic_passOver是一个字典,用于跟踪节点是否被访问
solution = (find_all_paths( graph, "M_glc_DASH_D_c', 'M_pyr_c', 'begin', dic_passOver ))
我的问题似乎是,一旦访问了路径,就无法再访问,因此其他可能的解决方案是不可能的。我通过在161处添加最大递归量来解释这一点,其中找到了我的特定代码的所有可能路由。
if passOver.values()[y][z] < 161 :
passOver.values()[y][z] = passOver.values()[y][z] + 1
但是,这看起来非常低效,而且我的大部分数据都是带有数千个索引的图表。此外,我不知道查找所有路由的允许节点访问量。数字161是手动计算出来的。
答案 0 :(得分:3)
好吧,我无法理解你对图表的表示。但这是一种通用算法,可用于查找避免无限循环的所有路径。
首先,您需要将图表表示为将节点映射到它们所连接的节点集的字典。例如:
graph = {'A':{'B','C'}, 'B':{'D'}, 'C':{'D'}}
这意味着从A
开始,您可以转到B
和C
。从B
,您可以转到D
,也可以从C
转到D
。我们假设链接是单向的。如果您希望它们是双向的,只需添加链接以便双向进行。
如果您以这种方式表示图表,则可以使用以下函数查找所有路径:
def find_all_paths(start, end, graph, visited=None):
if visited is None:
visited = set()
visited |= {start}
for node in graph[start]:
if node in visited:
continue
if node == end:
yield [start,end]
else:
for path in find_all_paths(node, end, graph, visited):
yield [start] + path
使用示例:
>>> graph = {'A':{'B','C'}, 'B':{'D'}, 'C':{'D'}}
>>> for path in find_all_paths('A','D', graph):
... print path
...
['A', 'C', 'D']
['A', 'B', 'D']
>>>
编辑以考虑澄清图表表示的评论
下面是一个函数,用于转换图形表示(假设我理解正确并且路由是双向的)到上面算法中使用的那个
def change_graph_representation(graph):
reverse_graph = {}
for node, links in graph.items():
for link in links:
if link not in reverse_graph:
reverse_graph[link] = set()
reverse_graph[link].add(node)
result = {}
for node,links in graph.items():
adj = set()
for link in links:
adj |= reverse_graph[link]
adj -= {node}
result[node] = adj
return result
如果根据链接找到路径很重要,而不是遍历的节点,则可以保留此信息,如下所示:
def change_graph_representation(graph):
reverse_graph = {}
for node, links in graph.items():
for link in links:
if link not in reverse_graph:
reverse_graph[link] = set()
reverse_graph[link].add(node)
result = {}
for node,links in graph.items():
adj = {}
for link in links:
for n in reverse_graph[link]:
adj[n] = link
del(adj[node])
result[node] = adj
return result
并使用此修改后的搜索:
def find_all_paths(start, end, graph, visited=None):
if visited is None:
visited = set()
visited |= {start}
for node,link in graph[start].items():
if node in visited:
continue
if node == end:
yield [link]
else:
for path in find_all_paths(node, end, graph, visited):
yield [link] + path
这将为您提供跟踪链接而不是遍历节点的路径。希望这会有所帮助:)