All possible combination of pairs + 1 triple group from an odd list?

随声附和 提交于 2021-02-10 14:35:16

问题


Starting with an odd list of students, let’s say 21 total:

cohort = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] 

I want use Python to write a function that assign pairs for group projects every day with different pairings. Since we have an odd number of students, I don’t want anyone to be working alone, so we would need to have 9 groups of 2 people and 1 group of 3 people. Every day they would change partners. For example, on day 1 and day 2, the groups would look like this:

[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11), (12, 13), (14, 15), (16, 17), (18, 19, 20)]
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10), (11, 12), (13, 14), (15, 16), (17, 18), (19, 20, 0)]

And so on. The order of the pairs isn’t important, so (0, 1) = (1, 0) and (0, 1, 2) = (2, 1, 0) = (1, 2, 0), etc.

How can I write a function in Python to print all possible configurations for the class pairings? I would like to see all the lists for each day and know how long it will take for everyone to work together at least once.

I looked into round robin scheduling algorithms and itertools.combinations, but haven't found a graceful solution for how to account for the final tuple of 3 created by the odd group number. I started writing the following function to get all possible two-people pairings from the following list, but I know this isn't quite going in the right direction, but I'm not sure how to proceed with making the list of groups (maybe they need to be unordered sets instead?) for each day…

def all_pairs(cohort):
    result = []
    for person1 in range(len(cohort)):
            for person2 in range(person1+1,len(cohort)):
                    result.append([cohort[person1],cohort[person2]])
    return result

pairings = all_pairs(cohort)
num_pairs = len(pairings)
print(f"{num_pairs} pairings")
for pair in pairings:
    print(pair)

回答1:


This is borderline asking for a program implementation but I'll answer anyway. Simply assume that the last 3 people in the list will form the 3-person group, then rotate the student list every day:

def pairings_on_day(students, day):
    # Create today's list by copying the original list of students
    bag = students.copy()
    pairs = []
    # Rotate the list
    for _ in range(day):
        bag.append(bag.pop(0))
    # Remove all 2-person groups from the list
    while len(bag) > 3:
        pairs.append((bag.pop(0), bag.pop(0)))
    pairs.append(tuple(bag))
    return pairs


def all_pairings(students):
    ret = []
    for i in range(len(students)):
        ret.append(pairings_on_day(students, i))
    return ret

Of course, this could be optimized by a lot, but it is an intuitive implementation.




回答2:


First, let's attack the theoretical minimum for the problem. You have N students and you want to know how long it will take to cycle through all possible pairings. This is "simple" algebra.

There are N*(N-1) / 2 pairings; this is a well-known formula.

On each day, you have (N-1)/2 pairs, plus the triple, which is 3 pairings: AB, AC, BC. This is a total of (N-1)/2 + 3 pairings per day.

Thus, your required number of days is

  ceil( (N*(N-1) / 2) / ((N-1)/2 + 3) )
= ceil( N*(N-1) / (N+5) )

A quick estimate gives weight to this. Most days, a student works with one other person, except for the "triplet" days, when they work with two. So it should take them a little less than N-1 days to work with N-1 other students.

As for the algorithm, here's your starting point for exploration: use the standard RR (round-robin) scheduling for an odd number of teams (where BYE is the stable element), but then add the idle team (student) to the adjacent pairing to make your triple. For instance, for 7 students, your rotation looks like this:

Rotation      Pairs
B  1  2  3    16 25 34 - 7
7  6  5  4   

B  7  1  2    75 14 23 - 6
6  5  4  3

B  6  7  1    64 73 12 - 5
5  4  3  2

B  5  6  7    53 62 71 - 4
4  3  2  1

Now ... how can you best allocate the soliton element to a pair, such that you make best use of that triplet group? Applying the formula, we have a minimum of

ceil(7 * 6 / 12) = 4 days

Can you find the way to make it happen with the above cycling?

If not, can you instead use one or two of the unlisted 3 cycles to make it work? (Hint: replace the 2nd or 3rd cycle above with the 6th).


I'll let you take it from here. :-)




回答3:


The round robin algorithm does a pretty good job for this. For an odd number of participants, you have to consider that one of them sits out each day.

def roundRobin(students):
    count     = len(students)
    even      = 1-(count&1)
    poly      = students[even:]
    for _ in range(count-even):
        pairs  = [(students[0],poly[0])]*even
        pairs += [(poly[i],poly[count-i-even]) for i in range(1,(count+1)//2)]
        yield(pairs)
        poly = poly[1:]+poly[:1]

output:

students = list(range(1,21+1))    
for day,pairs in enumerate(roundRobin(students),1):
    sitout = set(students).difference(*pairs)
    print(day,sitout, *pairs,)

day, sit-out, pairs:

1 {1} (2, 21) (3, 20) (4, 19) (5, 18) (6, 17) (7, 16) (8, 15) (9, 14) (10, 13) (11, 12)
2 {2} (3, 1) (4, 21) (5, 20) (6, 19) (7, 18) (8, 17) (9, 16) (10, 15) (11, 14) (12, 13)
3 {3} (4, 2) (5, 1) (6, 21) (7, 20) (8, 19) (9, 18) (10, 17) (11, 16) (12, 15) (13, 14)
4 {4} (5, 3) (6, 2) (7, 1) (8, 21) (9, 20) (10, 19) (11, 18) (12, 17) (13, 16) (14, 15)
5 {5} (6, 4) (7, 3) (8, 2) (9, 1) (10, 21) (11, 20) (12, 19) (13, 18) (14, 17) (15, 16)
6 {6} (7, 5) (8, 4) (9, 3) (10, 2) (11, 1) (12, 21) (13, 20) (14, 19) (15, 18) (16, 17)
7 {7} (8, 6) (9, 5) (10, 4) (11, 3) (12, 2) (13, 1) (14, 21) (15, 20) (16, 19) (17, 18)
8 {8} (9, 7) (10, 6) (11, 5) (12, 4) (13, 3) (14, 2) (15, 1) (16, 21) (17, 20) (18, 19)
9 {9} (10, 8) (11, 7) (12, 6) (13, 5) (14, 4) (15, 3) (16, 2) (17, 1) (18, 21) (19, 20)
10 {10} (11, 9) (12, 8) (13, 7) (14, 6) (15, 5) (16, 4) (17, 3) (18, 2) (19, 1) (20, 21)
11 {11} (12, 10) (13, 9) (14, 8) (15, 7) (16, 6) (17, 5) (18, 4) (19, 3) (20, 2) (21, 1)
12 {12} (13, 11) (14, 10) (15, 9) (16, 8) (17, 7) (18, 6) (19, 5) (20, 4) (21, 3) (1, 2)
13 {13} (14, 12) (15, 11) (16, 10) (17, 9) (18, 8) (19, 7) (20, 6) (21, 5) (1, 4) (2, 3)
14 {14} (15, 13) (16, 12) (17, 11) (18, 10) (19, 9) (20, 8) (21, 7) (1, 6) (2, 5) (3, 4)
15 {15} (16, 14) (17, 13) (18, 12) (19, 11) (20, 10) (21, 9) (1, 8) (2, 7) (3, 6) (4, 5)
16 {16} (17, 15) (18, 14) (19, 13) (20, 12) (21, 11) (1, 10) (2, 9) (3, 8) (4, 7) (5, 6)
17 {17} (18, 16) (19, 15) (20, 14) (21, 13) (1, 12) (2, 11) (3, 10) (4, 9) (5, 8) (6, 7)
18 {18} (19, 17) (20, 16) (21, 15) (1, 14) (2, 13) (3, 12) (4, 11) (5, 10) (6, 9) (7, 8)
19 {19} (20, 18) (21, 17) (1, 16) (2, 15) (3, 14) (4, 13) (5, 12) (6, 11) (7, 10) (8, 9)
20 {20} (21, 19) (1, 18) (2, 17) (3, 16) (4, 15) (5, 14) (6, 13) (7, 12) (8, 11) (9, 10)
21 {21} (1, 20) (2, 19) (3, 18) (4, 17) (5, 16) (6, 15) (7, 14) (8, 13) (9, 12) (10, 11)

Every student has been paired with every other students over 21 days. Every student has been the sit-out only once.

If instead of having one student sit-out each day, you form a group of 3, you will be making 12 pairings per day (i.e. 9 pairs plus 3 pairs for the group of 3). Even if you could magically avoid re-pairing students for the first 17 days, you would be left with one weird day at the end where you need to form 6 pairs and leave 9 students out which would probably be unfair to them. The one-sit-out per day approach is a lot more manageable (and fair)




回答4:


I am interested in the number of all the valid configurations, and I don't think it is possible to print out all.

Let us give all the paring positions their corresponding labels, something like,

[(A, B), (C, D), (E, F), (G, H), (I, J), (K, L), (M, N), (O, P), (Q, R), (S, T, U)]

We can always assign different students to different labels. For instance, the following configuration

[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11), (12, 13), (14, 15), (16, 17), (18, 19, 20)]

would mean student 0 → A, student 1 → B, etc. Actually, any possible rearrangement of the student numbers would yield a way to group students. There are totally 51,090,942,171,709,400,000 possibilities for 21 students (i.e. 21 numbers). (I calculated the number from this site)

The 2 facts that 1) order does matter within each group; 2) the order of the groups does not matter, would eliminate some duplicated configurations. My brain quickly produced an equation for this situation: P(21, 18) / 2^9 / P(10, 10) = 2,291,551,762. (Choosing 18 people to get arrangement, while the order of the rest 3 people does not matter. Each arrangement has its duplication, where the 9 paired groups can flip their order. Finally, the order of the 10 groups does not matter.)

The fact that "Every day they would change partners" would further eliminate more configurations given the first arrangement of the students. A quick equation I came up with is:

{P(21, 18) / 2^9 - 9 * [P(19, 16) / 2^8] - P(18, 18) / 2^9)} / P(10, 10) = 2,091,687,097.

The second term means one of the nine pairs remains unchanged, and the third term means the last triplet remains unchanged.

In summary, the first day you would have 2,291,551,762 options, with 2,091,687,097 options for the successive days.

It is hard to sample these valid configurations. A naïve Monte Carlo algorithm would lead to an accepting probability of ~1e-11. I am looking forward to advanced solutions.



来源:https://stackoverflow.com/questions/65896298/all-possible-combination-of-pairs-1-triple-group-from-an-odd-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!