Secret santa-Algorithmus
Jedes Jahr zu Weihnachten ziehen wir Namen für Geschenk-Austausch in meiner Familie. Dies erfordert in der Regel mehrere Ansichten, bis niemand gezogen hat, Ihr Gatte. Daher habe ich dieses Jahr codiert, meinen eigenen Namen zu zeichnen-app, die in ein paar Namen, ein paar der nicht erlaubten Paarungen und sendet aus einer E-Mail an alle mit Ihren gewählten giftee.
Gerade jetzt, der Algorithmus funktioniert wie folgt (in pseudocode):
function DrawNames(list allPeople, map disallowedPairs) returns map
//Make a list of potential candidates
foreach person in allPeople
person.potentialGiftees = People
person.potentialGiftees.Remove(person)
foreach pair in disallowedPairs
if pair.first = person
person.Remove(pair.second)
//Loop through everyone and draw names
while allPeople.count > 0
currentPerson = allPeople.findPersonWithLeastPotentialGiftees
giftee = pickRandomPersonFrom(currentPerson.potentialGiftees)
matches[currentPerson] = giftee
allPeople.Remove(currentPerson)
foreach person in allPeople
person.RemoveIfExists(giftee)
return matches
Tut wer weiß mehr über Graphentheorie wissen, eine Art von Algorithmus, der besser funktionieren würde hier? Für meine Zwecke funktioniert, aber ich bin neugierig.
EDIT: Da die E-Mails gingen eine Weile her, und ich bin nur in der Hoffnung, etwas zu lernen, werde ich anders formulieren dies als eine graph-Theorie in Frage. Ich bin nicht so interessiert in den besonderen Fällen, in denen die AUSSCHLÜSSE sind alle Paare (wie bei Ehegatten nicht immer gegenseitig). Ich bin mehr daran interessiert, in den Fällen, in denen es genug gibt AUSSCHLÜSSE, die Suche nach einer Lösung wird der harte Teil. Meine obige Algorithmus ist ein einfacher greedy-Algorithmus, dass ich nicht sicher bin, gelingen würde, in allen Fällen.
Beginnend mit einem vollständigen gerichteten Graphen und eine Liste von vertex-Paare. Für jeden vertex koppeln, entfernen Sie das edge von der ersten Ecke der zweiten.
Das Ziel ist ein graph, wo jeder Knoten hat eine Kante kommen, und eine Kante verlassen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nur einen Graphen mit Kanten zwischen zwei Menschen, wenn Sie berechtigt sind, Gaben zu teilen, und verwenden Sie dann ein perfektes matching Algorithmus. (Siehe "Pfade, Bäume und Blumen" für die (kluge) - Algorithmus)
Ich würde es nicht verwenden nicht erlaubte Paarungen, denn das erhöht die Komplexität des Problems. Geben Sie einfach jeden Namen und Adresse in eine Liste. Erstellen Sie eine Kopie der Liste und halten Sie mischen, bis die Adressen in jeder position der beiden Listen nicht übereinstimmen. Dadurch wird sichergestellt, dass niemand sich selbst oder Ihren Ehepartner.
Als bonus, wenn Sie wollen, um dieses Geheimnis-Stimmzettel-Stil, drucken von Umschlägen aus der ersten Liste und die Namen aus der zweiten Liste. Nicht spicken, während die Füllung Umschläge. (Oder Sie könnten einfach automatisieren E-Mail-Versand jeder thier-pick.)
Gibt es noch mehr Lösungen zu diesem problem auf dieser thread.
War ich gerade auch Tue, am Ende des Algorithmus verwendete ich nicht genau, Modell-Zeichnung Namen aus einem Hut, aber es ist verdammt nah dran. Im Grunde schieben Sie die Liste, und dann Paaren Sie jede person mit der nächsten person in der Liste. Der einzige Unterschied mit der Zeichnung Namen aus einem Hut ist, dass Sie einen Zyklus statt der potenziell erste mini-Untergruppen von Menschen, die nur Geschenke austauschen mit einander. Wenn alles, was könnte ein feature sein.
Implementierung in Python:
Hmmm. Ich belegte einen Kurs in der Graphentheorie, aber einfacher ist es, einfach zufällig permutiert Ihrer Liste, Paaren Sie jede aufeinander folgende Gruppe, tauschen Sie jedes element, das nicht erlaubt ist mit einem anderen. Da es keine nicht zugelassenen person in jedem paar, der swap wird immer erfolgreich sein, wenn Sie nicht zulassen, dass swaps mit der Gruppe ausgewählt. Ihr Algorithmus ist zu Komplex.
Erstellen Sie einen graph, wo jeder Kante ist "giftability" Eckpunkte darstellen Ehegatten NICHT benachbart sein. Wählen Sie eine Kante im random (ist ein Geschenk-Belegung). Löschen Sie alle Kanten kommen vom gifter, und alle Kanten, gehen an den Empfänger und wiederholen.
Es ist ein Konzept in der Graphentheorie bezeichnet ein Hamiltonian Circuit, das beschreibt, "Ziel", die Sie beschreiben. Ein Tipp für jeden, der findet, dies ist, um Benutzer zu sagen, welche "Samen" wurde verwendet, um die graph. Auf diese Weise, wenn Sie haben, zu re-generieren, die Grafik, die Sie kann. Der "Samen" ist auch nützlich, wenn Sie zum hinzufügen oder entfernen einer person. In diesem Fall wählen Sie einfach einen neuen "seed" und erzeugen einen neuen Graphen, so dass Sie sicher, dass die Teilnehmer, welche "Samen" ist der aktuelle/neueste.
Ich gerade eine web-app, die genau dies tun - http://www.secretsantaswap.com/
Mein Algorithmus ermöglicht Untergruppen. Es ist nicht schön, aber es funktioniert.
Arbeitet wie folgt:
1. zuweisen einer eindeutigen Kennung an alle Teilnehmer erinnern, welche Untergruppe Sie sind in
2. duplizieren und Zufall, dass die Liste (die Ziele)
3. erstellen Sie ein array mit der Anzahl der Teilnehmer in jeder Untergruppe
4. doppelte array aus [3] Ziele
5. erstellen Sie ein neues array für die final-matches
6. Durchlaufen die Teilnehmer die Zuordnung der erste Gegner, der nicht mit einem der folgenden Kriterien:
A. Teilnehmer == Ziel
B. Teilnehmer.Untergruppe == Ziel.Untergruppe
C. die Wahl der Zielgruppe wird zu einer Untergruppe scheitern in der Zukunft (z.B. Untergruppe 1 muss immer mindestens so viele nicht-Untergruppe 1 Ziele übrig als Teilnehmer Untergruppe 1 Teilnehmer übrig ist)
D. Teilnehmer(n+1) == Ziel (n +1)
Weisen wir Gegner wir auch Dekrementieren-arrays aus 3 und 4
So, nicht schön (an alle), aber es funktioniert. Hoffe es hilft,
Dan Carlson
Hier eine einfache Implementierung in java für die secret santa-problem.
Python-Lösung hier.
Gegeben eine Sequenz von
(person, tags)
, wo tags ist selbst eine (möglicherweise leere) Sequenz von Zeichenfolgen, mein Algorithmus schlägt vor, eine Kette von Personen, wobei jede person gibt ein Geschenk an den nächsten in der Kette (die Letzte person, die offensichtlich gekoppelt ist mit dem ersten).Den tags vorhanden sind, so dass die Personen gruppiert werden können, und jedes mal, wenn die nächste person ist gewählt aus der Gruppe, die am meisten dis-zusammengeschlossen, um die person, die zuletzt gewählt. Die erste person gewählt ist, durch einen leeren Satz von tags, so wird es ausgewählt werden aus der ältesten Gruppe.
Also, gegeben eine Eingabe-Sequenz:
einen Vorschlag:
['person1 [Männlich,weltweit1]',
'person2 [weiblich,company2]',
'person3 [Männlich,weltweit1]',
'wife2 [weiblich,marriage2,company2]',
'husband1 [Männlich,marriage1,company2]',
'husband2 [Männlich,marriage2,company3]',
'wife1 [weiblich,marriage1,weltweit1]']
Natürlich, wenn alle Personen, die keine tags (z.B. ein leeres Tupel), dann gibt es nur eine Gruppe, zum von zu wählen.
Gibt es nicht immer eine optimale Lösung (denken Sie an eine Eingabe-Sequenz von 10 Frauen und 2 Männer, Ihre genre-dem einzigen tag gegeben), aber er hat eine gute Arbeit, so viel, wie Sie können.
Py2/3 kompatibel.