简体   繁体   中英

Algorithm to distribute n people in unique pairs over n-1 days

I`m trying to create an algorithm which creates unique pairs out of an even number of n people. Afterwards it should partition these pairs into n-1 days. so every day, every person meets someone else. pairs shouldn't be duplicated. the algorithm should provide a different solution every time it runs.

eg my start array is [1,2,3,4] - this gets converted into following pairs:

[1,2],[1,3],[1,4],
      [2,3],[2,4],
            [3,4]

now these pairs need to be split up between n-1 days like this

day 1 [1,2] & [3,4]
day 2 [1,3] & [2,4]
day 3 [1,4] & [2,3]

thanks for your help!

UPDATE

Thanks to the answers I wrote this solution

    fun createDates(userIds: List<Int>): List<DateEntity> {
        val dates = ArrayList<DateEntity>()

        val userCount = userIds.size
        val days = userCount - 1
        val half = userCount / 2

        val mutableUsers = userIds.toMutableList()

        for (day in 0 until days) {
            val firstHalf = mutableUsers.slice(0 until half)
            val secondHalf = mutableUsers.slice(half until userCount).reversed()

            for (i in firstHalf.indices) {
                dates.add(DateEntity(day, firstHalf[i], secondHalf[i]))
            }
            // rotating the array
            mutableUsers.add(1, mutableUsers.removeLast())
        }
        return dates
    }

Round-robin algorithm:

Put people in two rows.

Every day person from the top row is paired with corresponding one from lower row. If number of persons is odd, one person waits for a day.

day 1
A B C
D E F
A:D B:E C:F

After the day shift all but the first person in cyclic manner:

day 2
A D B
E F C
A:E D:F B:C 

day 3
A E D
F C B
A:F E:C D:B

and so on.

This code simply performs the algorithm described by MBo.

 const cycle = (n, xs) => [... xs.slice (n % xs.length), ... xs.slice (0, n % xs.length)] const pairs = (xs) => xs.length < 2? []: [[xs [0], xs [xs.length - 1]], ...pairs (xs.slice (1, -1))] const roundRobin = ([x, ...xs]) => Array.from(xs, (_, i) => pairs ([x, ...cycle(i, xs)])) console.log (roundRobin ([1, 2, 3, 4, 5, 6])) //=> // (1 - 6) & (2 - 5) & (3 - 4) // (1 - 2) & (3 - 6) & (4 - 5) // (1 - 3) & (4 - 2) & (5 - 6) // (1 - 4) & (5 - 3) & (6 - 2) // (1 - 5) & (6 - 4) & (2 - 3)
 .as-console-wrapper {max-height: 100%;important: top: 0}

cycle just cycles an array n places, so that, for instance, cycle (2, ['a', 'b', 'c', 'd', 'e']) yields ['c', 'd', 'e', 'a', 'b'] . pairs puts into pairs the two elements from the ends of the array and then the two next to them, and so forth. pairs (['a', 'b', 'c', 'd', 'e', 'f']) yields [['a', 'f'], ['b', 'e'], ['c', 'd']] .

We combine these in roundRobin , For each day, we remove the first value, cycle the remaining ones, put the first value back, and turn the list into pairs.

If you want additional randomness, I would suggest simply shuffling the array before you start.

If you want to allow an odd number of participants, with one sitting out each time, I would add a dedicated sitting-out participant, which will then be paired each day with a different participant.

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