寻找对的组合(连接)

时间:2017-01-16 16:55:59

标签: python combinations itertools

我对Python特别感兴趣,但也非常感谢通用解决方案。我有一个偶数个节点(对于一个特定的例子,让我们说12个):

  

[' a1',' a2',' a3',' b1',' b2',& #39; b3',' c1',' c2',' c3',' d1',' d2&# 39;,' d3']

每个节点必须连接到另一个节点,形成6个连接(对)。 我需要找到一种方法来找到所有可能的连接组合。 此外,'a1'-'a2'应被视为与'a2'-'a1'

相同

一些想法:

  • 我可以获取可能itertools.combinations(lst, 2)的列表,但节点不可重用。比如,连接'a1'<->'a2'应该从'a1'<->'a3'已使用的可用选项中删除'a1'

  • 我不知道搜索是否适用,因为似乎存在一些问题:

    • 似乎没有(简单,便宜)跟踪访问状态的方式
    • 解决方案将始终位于底部(需要遍历所有树 完成所有连接的方式)

2 个答案:

答案 0 :(得分:3)

这是针对您的问题的递归解决方案:

def findPairs(l):
    # recursion anchor, basic case:
    # when we have 2 nodes only one pair is possible
    if len(l) == 2:
        yield [tuple(l)]
    else:
        # Pair the first node with all the others
        for i in range(1, len(l)):
            # Current pair
            pair1 = [(l[0], l[i])]
            # Combine it with all pairs among the remaining nodes
            remaining = l[1:i] + l[i+1:]
            for otherPairs in findPairs(remaining):
                yield pair1 + otherPairs

可以相应地计算所有解决方案的数量:

def N(n):
    if n == 2:
        return 1
    return (n-1) * N(n-2)

请注意,我没有检查n % 2 == 0

同样对于n==len(l)==12,您将获得10395种可能的组合,这是非常可行的。但是这段代码虽然简短易读,却一遍又一遍地生成和重新生成列表和元组,这使得它变慢。
看看它是否足够快,否则我们将不得不调整它。

答案 1 :(得分:1)

我认为你只需要使用排列和take adjacent pairs 删除任何反向订单重复:

nodes = 'A1 A2 B1 B2 C1 C2'.split()
perms = set()
for perm in itertools.permutations(nodes):
    p = tuple(sorted(
        [tuple(sorted(perm[i:i + 2])) for i in range(0, len(perm), 2)]))
    perms.add(p)

for perm in sorted(perms):
    print(perm)

那么这是如何运作的呢?

我们需要循环遍历节点的每个排列:

for perm in itertools.permutations(nodes):

然后在排列中从相邻节点创建对:

[tuple(sorted(perm[i:i + 2])) for i in range(0, len(perm), 2)]

这是通过获取两个相邻节点并对它们进行排序来完成的 可以在以后寻找傻瓜:

tuple(sorted(perm[i:i + 2]))

然后创建tuple,以便我们允许immutable 索引。然后将所有对进行一次排列并执行相同的操作 sort并转换为tuple整个排列:

p = tuple(sorted(
    [tuple(sorted(perm[i:i + 2])) for i in range(0, len(perm), 2)]))

然后将排列添加到set,这会删除重复项:

perms.add(p)

打印结果:

for perm in sorted(perms):
    print(perm)