我编写了一个递归函数,以给定的图边列表作为元组在图中找到一条简单路径(只有一条路径)。例如:
edges = [(0, 10),(2, 16),(4, 5),(6, 24),(7, 6),(8, 23),(9, 25),(10, 14),(11, 1),(12, 19),(13, 22),(14, 15),(15, 11),(16, 7),(17, 21),(18, 13),(19, 17),(20, 8),(21, 3),(22, 20),(23, 12),(24, 9),(25, 18)]
def get_path(sol, start, end):
out = []
for i,j in sol:
if i == start:
out.append(i)
out += get_path(sol, j, end)
if j == end:
out.append(j)
return out
但是,如果我无法在返回列表中正确获取结束节点。如果删除第7行和第8行,则最后一个节点将不出现在我的解决方案中,并且如果代码中包含这些行,则我的解决方案将获得多个结束节点。例如:
get_path(edges, 2, 3)
path = [2, 16, 7, 11, 15, 14, 10, 22, 13, 18, 25, 21, 17, 19, 12, 9, 24, 6, 8, 20, 23]
我们可以看到结束节点是3
,它应该是列表的最后一个元素。非常感谢您的投入。谢谢
答案 0 :(得分:2)
您可以使用networkX
。您可以从边缘定义网络并获得两个给定节点之间的简单路径。我正在使用nx.shortest_simple_paths
,但是您可以使用all_simple_paths
来全部获取它们:
import networkx as nx
G=nx.Graph()
G.add_edges_from(edges)
next(nx.shortest_simple_paths(G, 2, 3))
# [2, 16, 7, 6, 24, 9, 25, 18, 13, 22, 20, 8, 23, 12, 19, 17, 21, 3]
答案 1 :(得分:0)
您的代码中的每个递归调用都会进行一次迭代,其中j == end
为真,因此您确实会多次添加它:与递归深度一样多。
如果将结束条件放在循环之外,效果会更好,如下所示:
if start == end:
return [start]
因此,只需稍作修改,您的代码将如下所示:
def get_path(sol, start, end):
if start == end:
return [start]
out = []
for i,j in sol:
if i == start:
out.append(i)
out += get_path(sol, j, end)
return out
其他一些评论:
您可以一次性在if
块中执行两个列表操作:
out += [i] + get_path(sol, j, end)
遍历每个列表中的完整列表效率非常低 递归调用。最好先建一个键控的字典 按起始编号。这样一来,您不必反复查找 相应的边缘。
似乎您的代码期望图形是一个链,没有任何
有2个或更多输出边缘的节点。如果发生这种情况,if i == start:
块将执行多次,导致输出尴尬。对于此类情况,也不太困难
代码:
from collections import defaultdict
def get_path(sol, start, end):
# Transform to dict
d = defaultdict(list)
for i,j in sol:
d[i] += [j]
def recur(start):
if start == end:
return [start]
for nxt in d[start]:
path = recur(nxt)
if path is not None:
return [start] + path
return recur(start)
edges = [(0, 10),(2, 16),(4, 5),(6, 24),(7, 6),(8, 23),(9, 25),(10, 14),
(11, 1),(12, 19),(13, 22),(14, 15),(15, 11),(16, 7),(17, 21),
(18, 13),(19, 17),(20, 8),(21, 3),(22, 20),(23, 12),(24, 9),(25, 18)]
path = get_path(edges, 2, 3)
print (path)