我认为这是一个相当困难的问题。所以,提前感谢您的帮助。
我有一个我正在遍历的图表,一次创建一个不同的路径。 我有一套边缘我必须"使用,每个都存储为(to,from)的元组。我避免重复节点,所以我们只去每个"到#34;一次,每次"来自"一旦。我也不想在组合中创建一个循环。
我想创建边的所有组合(顺序很重要)。具体来说,我想要所有有效大小的元组的所有组合。
清晰的一些例子:
Valid combinations of edges:
((5,7))
((3,9),(9,11),(21,18))
((1,2),(2,3),(3,4),(4,5))
Invalid combinations:
((9,8),(9,6))
((2,5),(11,3),(8,5))
((1,2),(2,3),(3,4),(4,1))
所以,我们可以看到的一件事是,要制作所有组合,我们将制作大小为1的组合,然后是大小为2,然后为3,... 4 .... n
不用担心,这并不是很疯狂。我创建组合的边缘数量通常不是那么多。但它是可变的,谁知道,也许我最终可能会创建一些大小为n的组合。所以,我正在考虑使用itertools来生成组合。我可以在循环中放置itertools组合,并增加每次传递组合的大小。
但后来我才意识到,大多数组合实际上可能最终无效,如果我使用itertools,我不认为我可以检查它们的有效性,直到生成整个组合。这看起来非常低效。
所以,我的思考就是使用邻接列表,其中我要强制的任何边(to,from)存储在indices [to] [from]中。这允许我迭代邻接列表,以避免重复"或#34;来自"来自"。
但是,我仍然无法概念化我如何实际编写一个函数,通过遍历邻接列表生成我想要的所有组合。
任何想法?
注意:就目前而言,如果有人选择忽略避免封闭周期的挑战,我不介意,即:1,2,3,4,1
答案 0 :(得分:2)
以下是递归生成器函数。它将边缘列表预处理成邻接字典。它将生成长度为l
的所有路径:
from collections import defaultdict
# preprocess for better performance
edges = [(1,2),(2,1),(2,3),(3,4),(4,5),(5,7), (3,9),(9,11),(11,18)]
graph = defaultdict(set)
for f, t in edges:
graph[f].add(t)
def paths(graph, l, fr=None, avoid=None):
avoid = avoid or set() # avoid previous nodes
if l == 0: # base case: empty path
yield ()
from_nodes = [fr] if fr else graph.keys()
for f in from_nodes:
new_avoid = avoid | set([f]) # set union
for t in graph[f]: # for every adjacent node t...
if t not in avoid: # unless it has been seen
# take all paths starting at t with length l-1
for path in paths(graph, l-1, fr=t, avoid=new_avoid):
# and prepend the current edge
yield ((f, t),) + path
>>> list(paths(graph, 2))
[((1, 2), (2, 3)),
((2, 3), (3, 9)), # no cycle: ((1, 2), (2, 1))
((2, 3), (3, 4)),
((3, 9), (9, 11)),
((3, 4), (4, 5)),
((4, 5), (5, 7)),
((9, 11), (11, 18))]
>>> list(paths(graph, 3))
[((1, 2), (2, 3), (3, 9)),
((1, 2), (2, 3), (3, 4)),
((2, 3), (3, 9), (9, 11)),
((2, 3), (3, 4), (4, 5)),
((3, 9), (9, 11), (11, 18)),
((3, 4), (4, 5), (5, 7))]