Es gibt einen einfachen Algorithmus zum zufälligen Auswählen eines Artikels, bei dem Artikel individuelle Gewichte haben:
1) Berechnen Sie die Summe aller Gewichte
2) Wählen Sie eine Zufallszahl, die 0 oder größer ist und kleiner als die Summe der Gewichte ist
3) Gehen Sie die Artikel einzeln durch und subtrahieren Sie ihr Gewicht von Ihrer Zufallszahl, bis Sie den Artikel erhalten, bei dem die Zufallszahl geringer ist als das Gewicht dieses Artikels
Pseudocode zur Veranschaulichung:
int sum_of_weight = 0;
for(int i=0; i<num_choices; i++) {
sum_of_weight += choice_weight[i];
}
int rnd = random(sum_of_weight);
for(int i=0; i<num_choices; i++) {
if(rnd < choice_weight[i])
return i;
rnd -= choice_weight[i];
}
assert(!"should never get here");
Dies sollte einfach an Ihre Boost-Container und dergleichen anzupassen sein.
Wenn Ihre Gewichte selten geändert werden, Sie jedoch häufig zufällig eine auswählen und Ihr Container Zeiger auf die Objekte speichert oder mehr als ein paar Dutzend Elemente lang ist (im Grunde müssen Sie ein Profil erstellen, um zu wissen, ob dies hilft oder behindert). , dann gibt es eine Optimierung:
Durch Speichern der kumulierten Gewichtssumme in jedem Artikel können Sie mithilfe einer binären Suche den Artikel auswählen, der dem Kommissioniergewicht entspricht.
Wenn Sie die Anzahl der Elemente in der Liste nicht kennen, gibt es einen sehr übersichtlichen Algorithmus namens Reservoir Sampling , der zur Gewichtung angepasst werden kann.
A Monte Carlo method called Russian roulette is used to choose one of these actions
wird beim googeln in Eimern angezeigt. "Russischer Roulette-Algorithmus". Man könnte argumentieren, dass all diese Leute den falschen Namen haben.Aktualisierte Antwort auf eine alte Frage. Sie können dies in C ++ 11 ganz einfach mit std :: lib tun:
Ausgabe auf meinem System:
Beachten Sie, dass der größte Teil des obigen Codes nur der Anzeige und Analyse der Ausgabe gewidmet ist. Die eigentliche Generation besteht nur aus wenigen Codezeilen. Die Ausgabe zeigt, dass die angeforderten "Wahrscheinlichkeiten" erhalten wurden. Sie müssen die angeforderte Ausgabe durch 1,5 teilen, da dies die Anforderungen sind.
quelle
std::discrete_distribution
stattdessenstd::piecewise_constant_distribution
wäre es noch besser gewesen.Wenn sich Ihre Gewichte langsamer ändern als gezeichnet, ist C ++ 11
discrete_distribution
am einfachsten:Beachten Sie jedoch, dass c ++ 11
discrete_distribution
alle kumulierten Summen bei der Initialisierung berechnet. Normalerweise möchten Sie das, weil es die Abtastzeit für einmalige O (N) -Kosten beschleunigt. Für eine sich schnell ändernde Verteilung entstehen jedoch hohe Berechnungs- (und Speicher-) Kosten. Wenn die Gewichte beispielsweise die Anzahl der Elemente darstellen und jedes Mal, wenn Sie eines zeichnen, entfernen Sie es, möchten Sie wahrscheinlich einen benutzerdefinierten Algorithmus.Wills Antwort https://stackoverflow.com/a/1761646/837451 vermeidet diesen Overhead, ist jedoch langsamer zu zeichnen als C ++ 11, da keine binäre Suche verwendet werden kann.
Um dies zu sehen, können Sie die relevanten Zeilen sehen (
/usr/include/c++/5/bits/random.tcc
auf meiner Ubuntu 16.04 + GCC 5.3-Installation):quelle
Was ich mache, wenn ich Zahlen gewichten muss, ist die Verwendung einer Zufallszahl für das Gewicht.
Zum Beispiel: Ich brauche das, um Zufallszahlen von 1 bis 3 mit den folgenden Gewichten zu generieren:
Dann benutze ich:
Damit hat es zufällig 10% der Wahrscheinlichkeiten 1, 30% 2 und 60% 3.
Sie können damit nach Ihren Wünschen spielen.
Hoffe ich konnte dir helfen, viel Glück!
quelle
Erstellen Sie eine Tasche (oder std :: vector) aller Artikel, die ausgewählt werden können.
Stellen Sie sicher, dass die Anzahl der einzelnen Elemente proportional zu Ihrer Gewichtung ist.
Beispiel:
Haben Sie also eine Tasche mit 100 Artikeln mit 60 1er, 35 2er und 5 3er.
Sortieren Sie nun die Tasche nach dem Zufallsprinzip (std :: random_shuffle)
Nehmen Sie die Elemente nacheinander aus dem Beutel, bis er leer ist.
Sobald der Beutel leer ist, randomisieren Sie ihn erneut und beginnen Sie erneut.
quelle
1,2,2
1 1/3 der Zeit und 2 2/3. Randomisieren Sie das Array, wählen Sie das erste aus, sagen wir eine 2, jetzt folgt das nächste Element, das Sie auswählen, der Verteilung von 1 1/2 der Zeit und 2 1/2 der Zeit. Kapieren?Wählen Sie eine Zufallszahl für [0,1), die der Standardoperator () für ein Boost-RNG sein sollte. Wählen Sie den Artikel mit der kumulativen Wahrscheinlichkeitsdichtefunktion> = diese Zahl:
Wobei random01 () ein double> = 0 und <1 zurückgibt. Beachten Sie, dass für die obigen Schritte die Wahrscheinlichkeiten nicht 1 ergeben müssen. es normalisiert sie für dich.
p ist nur eine Funktion, die einem Element in der Sammlung eine Wahrscheinlichkeit zuweist [Anfang, Ende]. Sie können es weglassen (oder eine Identität verwenden), wenn Sie nur eine Folge von Wahrscheinlichkeiten haben.
quelle
Ich habe mehrere einfache gewichtete Zufallsalgorithmen implementiert .
quelle