--- title: Pair up! date: 2017-04-21 tags: [math] description: | Recently I stumbled upon a question that tickled my mathematical senses: I was in a workshop situation where we wanted to repeatedly split into pairs until everyone had talked to everyone. How could this be done? --- Recently I stumbled upon a question that tickled my mathematical senses. It seemed simple enough but not too simple: I was in a workshop situation where we wanted to repeatedly split into pairs until everyone had talked to everyone. How could this be done? Measures of quality of the algorithm would be: - Should be finished after a minimal number of rounds. - No person should be singled out. - It should be simple to explain what everyone has to do. ## First approach: Lower bound In a group of `n` people, there are `n * (n - 1) / 2` pairs in total. At one time, there can be at most `floor(n / 2)` pairs. So if `n` is even the minimal number of rounds is `n - 1`, if it is odd it is `n`. This makes sense because each person has to speak to `n - 1` people. ## Second approach: Divide and conquer The problem can be solved with a simple recursive algorithm: Split into two groups of size `floor(n / 2)` and `ceil(n / 2)`. Have everyone from the one group talk to everyone from the other. This will take `ceil(n / 2)` rounds. Then repeat for each individual group until only one person is left per group. In each iteration, there can be one additional round necessary due to the rounding. In the worst case, this takes `n - 1 + log2(n - 1)` rounds. This algorithm is simple, but not optimal. Let's look at the example of `n = 6`: 1-4 2-5 3-6 1-5 2-6 3-4 1-6 2-4 3-5 1-2 4-5 1-3 4-6 2-3 5-6 In the later rounds we have people waiting who could pair up. We should skip the first round instead. ## Optimal solution: Distances Let's first concentrate on the case where `n` is odd. You have a row of tables with one pair each. On the end of a round, everyone moves to their left (clockwise). Because both you and the people on the other side of the table move, you skip over one person. On one end of the row of tables, you switch to the other side directly, so that you talk to people with an odd distance to your right from then on. On the other end, you have to skip one round, so that you talk to people with an even distance. If `n` is even, the whole thing will execute as if `n` was actually `n - 1` and you talk to person `n` instead of skipping a round on the end of the row. ![](./pairs.gif) Here is an implementation of this algorithm in python: ```python def pairs(n): is_even = n % 2 == 0 if is_even: n = n - 1 for _round in range(n): r = [] for i in range(int((n + 1) / 2)): r.append([]) for person in range(n): table = (_round + person) % n if table > n / 2: table = n - table r[table].append(person) if is_even: r[0].append(n + 1) print(r) ``` ## Conclusion The second algorithm actually is optimal in terms of time. It is also relatively easy to understand. The only issue is that, in the even case, person `n` has a special role. I would like to see how well this works in practice.