Secret santa algorithm

前端 未结 9 1407
温柔的废话
温柔的废话 2020-12-04 22:26

Every Christmas we draw names for gift exchanges in my family. This usually involves mulitple redraws until no one has pulled their spouse. So this year I coded up my own

相关标签:
9条回答
  • 2020-12-04 22:36

    I just created a web app that will do exactly this - http://www.secretsantaswap.com/

    My algorithm allows for subgroups. It's not pretty, but it works.

    Operates as follows:
    1. assign a unique identifier to all participants, remember which subgroup they're in
    2. duplicate and shuffle that list (the targets)
    3. create an array of the number of participants in each subgroup
    4. duplicate array from [3] for targets
    5. create a new array to hold the final matches
    6. iterate through participants assigning the first target that doesn't match any of the following criteria:
         A. participant == target
         B. participant.Subgroup == target.Subgroup
         C. choosing the target will cause a subgroup to fail in the future (e.g. subgroup 1 must always have at least as many non-subgroup 1 targets remaining as participants subgroup 1 participants remaining)
         D. participant(n+1) == target (n +1)
    If we assign the target we also decrement the arrays from 3 and 4

    So, not pretty (at all) but it works. Hope it helps,

    Dan Carlson

    0 讨论(0)
  • 2020-12-04 22:37

    I wouldn't use disallowed pairings, since that greatly increases the complexity of the problem. Just enter everyone's name and address into a list. Create a copy of the list and keep shuffling it until the addresses in each position of the two lists don't match. This will ensure that no one gets themselves, or their spouse.

    As a bonus, if you want to do this secret-ballot-style, print envelopes from the first list and names from the second list. Don't peek while stuffing the envelopes. (Or you could just automate emailing everyone thier pick.)

    There are even more solutions to this problem on this thread.

    0 讨论(0)
  • 2020-12-04 22:42

    Create a graph where each edge is "giftability" Vertices that represent Spouses will NOT be adjacent. Select an edge at random (that is a gift assignment). Delete all edges coming from the gifter and all edges going to the receiver and repeat.

    0 讨论(0)
  • 2020-12-04 22:43

    Hmmm. I took a course in graph theory, but simpler is to just randomly permute your list, pair each consecutive group, then swap any element that is disallowed with another. Since there's no disallowed person in any given pair, the swap will always succeed if you don't allow swaps with the group selected. Your algorithm is too complex.

    0 讨论(0)
  • 2020-12-04 22:46

    I was just doing this myself, in the end the algorithm I used doesn't exactly model drawing names out of a hat, but it's pretty damn close. Basically shuffle the list, and then pair each person with the next person in the list. The only difference with drawing names out of a hat is that you get one cycle instead of potentially getting mini subgroups of people who only exchange gifts with each other. If anything that might be a feature.

    Implementation in Python:

    import random
    from collections import deque
    def pairup(people):
        """ Given a list of people, assign each one a secret santa partner
        from the list and return the pairings as a dict. Implemented to always
        create a perfect cycle"""
        random.shuffle(people)
        partners = deque(people)
        partners.rotate()
        return dict(zip(people,partners))
    
    0 讨论(0)
  • 2020-12-04 22:47

    Here a simple implementation in java for the secret santa problem.

    public static void main(String[] args) {
        ArrayList<String> donor = new ArrayList<String>();
        donor.add("Micha");
        donor.add("Christoph");
        donor.add("Benj");
        donor.add("Andi");
        donor.add("Test");
        ArrayList<String> receiver = (ArrayList<String>) donor.clone();
    
        Collections.shuffle(donor);
        for (int i = 0; i < donor.size(); i++) {
            Collections.shuffle(receiver);
            int target = 0;
            if(receiver.get(target).equals(donor.get(i))){              
                target++;
            }           
            System.out.println(donor.get(i) + " => " + receiver.get(target));
            receiver.remove(receiver.get(target));
        }
    }
    
    0 讨论(0)
提交回复
热议问题