Datenstruktur für geladene Würfel?


130

Angenommen, ich habe einen n-seitig geladenen Würfel, bei dem jede Seite k eine gewisse Wahrscheinlichkeit p k hat , beim Würfeln hochzukommen. Ich bin gespannt, ob es einen guten Algorithmus zum statischen Speichern dieser Informationen gibt (dh für einen festen Satz von Wahrscheinlichkeiten), damit ich einen zufälligen Würfelwurf effizient simulieren kann.

Derzeit habe ich eine O (lg n) -Lösung für dieses Problem. Die Idee ist, eine Tabelle der kumulativen Wahrscheinlichkeit der ersten k Seiten für alle k zu speichern, eine zufällige reelle Zahl im Bereich [0, 1] zu erzeugen und eine binäre Suche über die Tabelle durchzuführen, um den größten Index zu erhalten, dessen kumulativ ist Wert ist nicht größer als der gewählte Wert. Ich mag diese Lösung eher, aber es scheint seltsam, dass die Laufzeit die Wahrscheinlichkeiten nicht berücksichtigt. Insbesondere in den extremen Fällen, in denen eine Seite immer auftaucht oder die Werte gleichmäßig verteilt sind, ist es möglich, das Ergebnis des Rollens in O (1) mit einem naiven Ansatz zu generieren, obwohl meine Lösung immer noch logarithmisch viele Schritte benötigt.

Hat jemand Vorschläge, wie dieses Problem auf eine Weise gelöst werden kann, die in der Laufzeit irgendwie "anpassungsfähig" ist?

EDIT : Basierend auf den Antworten auf diese Frage habe ich einen Artikel geschrieben, der viele Ansätze für dieses Problem zusammen mit ihren Analysen beschreibt. Es sieht so aus, als ob Voses Implementierung der Alias-Methode Θ (n) Vorverarbeitungszeit und O (1) Zeit pro Würfelwurf ergibt, was wirklich beeindruckend ist. Hoffentlich ist dies eine nützliche Ergänzung zu den Informationen in den Antworten!


2
Es ist vernünftig, dass es für jeden speziellen Fall eine O (1) -Lösung gibt .
Tim

Antworten:


117

Sie suchen nach der Alias-Methode, die eine O (1) -Methode zum Generieren einer festen diskreten Wahrscheinlichkeitsverteilung (vorausgesetzt, Sie können in konstanter Zeit auf Einträge in einem Array der Länge n zugreifen) mit einer einmaligen O (n) -Einstellung bereitstellt . Sie finden es dokumentiert in Kapitel 3 (PDF) von "Non-Uniform Random Variate Generation" von Luc Devroye.

Die Idee ist, Ihr Array von Wahrscheinlichkeiten p k zu nehmen und drei neue n-Element-Arrays zu erzeugen, q k , a k und b k . Jedes q k ist eine Wahrscheinlichkeit zwischen 0 und 1, und jedes a k und b k ist eine ganze Zahl zwischen 1 und n.

Wir erzeugen Zufallszahlen zwischen 1 und n, indem wir zwei Zufallszahlen r und s zwischen 0 und 1 erzeugen. Sei i = Etage (r * N) +1. Wenn q i <s ist, geben Sie a i zurück, andernfalls geben Sie b i zurück . Die Arbeit in der Alias-Methode besteht darin, herauszufinden, wie q k , a k und b k erzeugt werden .


Für einen solch nützlichen Algorithmus ist die Alias-Methode überraschenderweise nicht sehr bekannt.
mhum

Für die Aufzeichnung: Ich habe eine kleine C-Bibliothek für zufällige Stichproben mit der Alias-Methode apps.jcns.fz-juelich.de/ransampl veröffentlicht .
Joachim W

1
Eine bestimmte Implementierung der Alias-Methode kann langsamer sein als eine Methode mit schlechterer Zeitkomplexität, wie z. B. ein Roulette-Rad für eine bestimmte nund eine ausgewählte Anzahl von Zufallszahlen, die aufgrund konstanter Faktoren bei der Implementierung von Algorithmen generiert werden sollen.
JFS

4

Verwenden Sie einen ausgeglichenen binären Suchbaum (oder eine binäre Suche in einem Array) und erhalten Sie die Komplexität O (log n). Haben Sie einen Knoten für jedes Würfelergebnis und die Schlüssel sind das Intervall, das dieses Ergebnis auslöst.

function get_result(node, seed):
    if seed < node.interval.start:
        return get_result(node.left_child, seed)
    else if seed < node.interval.end:
        // start <= seed < end
        return node.result
    else:
        return get_result(node.right_child, seed)

Das Gute an dieser Lösung ist, dass sie sehr einfach zu implementieren ist, aber dennoch eine gute Komplexität aufweist.



Sie können garantieren, dass es ausgeglichen ist, wenn Sie es in der richtigen Reihenfolge konstruieren.
Hugomg

3

Ich denke daran, deinen Tisch zu granulieren.

Anstatt eine Tabelle mit der Summe für jeden Würfelwert zu haben, können Sie ein ganzzahliges Array mit der Länge xN erstellen, wobei x idealerweise eine hohe Zahl ist, um die Genauigkeit der Wahrscheinlichkeit zu erhöhen.

Füllen Sie dieses Array mit dem Index (normalisiert durch xN) als kumulativen Wert und speichern Sie in jedem 'Slot' im Array den möglichen Würfelwurf, wenn dieser Index angezeigt wird.

Vielleicht könnte ich es anhand eines Beispiels einfacher erklären:

Mit drei Würfeln: P (1) = 0,2, P (2) = 0,5, P (3) = 0,3

Erstellen Sie ein Array. In diesem Fall wähle ich eine einfache Länge, z. B. 10. (dh x = 3.33333)

arr[0] = 1,
arr[1] = 1,
arr[2] = 2,
arr[3] = 2,
arr[4] = 2,
arr[5] = 2,
arr[6] = 2,
arr[7] = 3,
arr[8] = 3,
arr[9] = 3

Um die Wahrscheinlichkeit zu ermitteln, randomisieren Sie einfach eine Zahl zwischen 0 und 10 und greifen Sie einfach auf diesen Index zu.

Diese Methode verliert möglicherweise an Genauigkeit, erhöht jedoch x und die Genauigkeit ist ausreichend.


1
Für volle Genauigkeit können Sie die Array-Suche als ersten Schritt durchführen und für Array-Intervalle, die mehreren Seiten entsprechen, dort eine Suche durchführen.
Aaz
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.