简体   繁体   中英

Finding combinations of pairs (connections)

I'm interested in Python specifically, but a generic solution would be also be much appreciated. I have an even number of nodes (let's say 12 for a particular example):

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

Each node must be connected to another node, forming 6 connections (pairs). I need to figure out a way to find all possible combinations of connections. Also, 'a1'-'a2' should be considered the the same as 'a2'-'a1'

Some thoughts:

  • I can get the list of possible itertools.combinations(lst, 2) , but nodes are not reusable. Say, a connection 'a1'<->'a2' should eliminate 'a1'<->'a3' from the available choices as 'a1' already used.

  • I have no idea if the search is even applicable as there seems to be a few problems:

    • there seems to be no (easy, cheap) way to track visited states
    • the solution will always be on the bottom (need to traverse the tree all the way down to complete all the connections)

Here is a recursive solution for your problem:

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

The number of all solutions can be calculated accordingly:

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

Note that I didn't check for n % 2 == 0 .

Also for n==len(l)==12 you'll get 10395 possible sets of combinations which is quite doable. But this code, while being short and readable, is gernerating and regenerating lists and tuples over and over again which makes it slow.
See if it's fast enough for you, otherwise we'll have to tweak it.

I think you just need to use permutations and take adjacent pairs , then remove any reversed order duplicates:

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)

So how does this work?

We need to loop over every permutation of the nodes:

for perm in itertools.permutations(nodes):

Then create pairs from adjacent nodes in the permutation:

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

This is done via taking two adjacent nodes and sorting them so we can look for dupes later:

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

and then creating a tuple so that we have something immutable to allow indexing. Then take all of the pairs for one permutation and perform the same sort and conversion to tuple for the entire permutation:

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

Then add the permutation to a set , which removes duplicates:

perms.add(p)

And print the results:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM