Ada algoritme langsung untuk memilih item secara acak, di mana item memiliki bobot individual:
1) hitung jumlah semua bobot
2) pilih nomor acak yang 0 atau lebih besar dan kurang dari jumlah bobot
3) periksa item satu per satu, kurangi bobotnya dari nomor acak Anda, sampai Anda mendapatkan item di mana nomor acaknya kurang dari bobot item itu
Pseudo-code menggambarkan ini:
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");
Ini harus mudah untuk disesuaikan dengan wadah penambah Anda dan semacamnya.
Jika bobot Anda jarang berubah tetapi Anda sering memilihnya secara acak, dan selama wadah Anda menyimpan pointer ke objek atau panjangnya lebih dari beberapa lusin (pada dasarnya, Anda harus membuat profil untuk mengetahui apakah ini membantu atau menghalangi) , lalu ada pengoptimalan:
Dengan menyimpan jumlah bobot kumulatif di setiap item, Anda dapat menggunakan pencarian biner untuk memilih item yang sesuai dengan bobot pick.
Jika Anda tidak mengetahui jumlah item dalam daftar, maka ada algoritme yang sangat rapi yang disebut reservoir sampling yang dapat disesuaikan untuk diberi bobot.
A Monte Carlo method called Russian roulette is used to choose one of these actions
itu muncul dalam keranjang saat mencari di Google. "algoritma roulette Rusia". Anda dapat membantah bahwa semua orang ini memiliki nama yang salah.Jawaban yang diperbarui untuk pertanyaan lama. Anda dapat dengan mudah melakukan ini di C ++ 11 hanya dengan std :: lib:
Output di sistem saya:
Perhatikan bahwa sebagian besar kode di atas dikhususkan untuk hanya menampilkan dan menganalisis keluaran. Generasi sebenarnya hanyalah beberapa baris kode. Outputnya menunjukkan bahwa "probabilitas" yang diminta telah diperoleh. Anda harus membagi output yang diminta dengan 1,5 karena itulah yang ditambahkan oleh permintaan.
sumber
std::discrete_distribution
bukannyastd::piecewise_constant_distribution
akan lebih baik.Jika bobot Anda berubah lebih lambat daripada yang digambar, C ++ 11
discrete_distribution
akan menjadi yang termudah:Perhatikan, bagaimanapun, bahwa c ++ 11
discrete_distribution
menghitung semua jumlah kumulatif saat inisialisasi. Biasanya, Anda menginginkannya karena mempercepat waktu pengambilan sampel untuk biaya satu kali O (N). Tetapi untuk distribusi yang berubah dengan cepat, ini akan menimbulkan biaya perhitungan (dan memori) yang berat. Misalnya jika bobot mewakili berapa banyak item yang ada dan setiap kali Anda menggambarnya, Anda menghapusnya, Anda mungkin menginginkan algoritme khusus.Jawaban Will https://stackoverflow.com/a/1761646/837451 menghindari overhead ini tetapi akan lebih lambat untuk diambil dari C ++ 11 karena tidak dapat menggunakan pencarian biner.
Untuk melihat bahwa ia melakukan ini, Anda dapat melihat baris yang relevan (
/usr/include/c++/5/bits/random.tcc
pada instalasi Ubuntu 16.04 + GCC 5.3 saya):sumber
Apa yang saya lakukan ketika saya perlu menimbang angka adalah menggunakan angka acak untuk menimbang.
Sebagai contoh: Saya perlu menghasilkan angka acak dari 1 hingga 3 dengan bobot sebagai berikut:
Kemudian saya menggunakan:
Dengan ini, secara acak memiliki 10% probabilitas menjadi 1, 30% menjadi 2 dan 60% menjadi 3.
Anda bisa bermain dengannya sesuai kebutuhan Anda.
Semoga saya bisa membantu Anda, Semoga Sukses!
sumber
Bangun tas (atau std :: vector) dari semua barang yang bisa diambil.
Pastikan jumlah setiap item proporsional dengan bobot Anda.
Contoh:
Jadi miliki tas dengan 100 item dengan 60 1, 35 2 dan 5 3.
Sekarang urutkan tas secara acak (std :: random_shuffle)
Pilih elemen dari tas secara berurutan sampai kosong.
Setelah kosong, atur ulang tasnya dan mulai lagi.
sumber
1,2,2
menghasilkan 1 1/3 dari waktu dan 2 2/3. Acak array, pilih yang pertama, katakanlah 2, sekarang elemen berikutnya yang Anda pilih mengikuti distribusi 1 1/2 waktu dan 2 1/2 waktu. Mengerti?Pilih nomor acak pada [0,1), yang seharusnya menjadi operator default () untuk meningkatkan RNG. Pilih item dengan fungsi kepadatan probabilitas kumulatif> = angka itu:
Di mana random01 () mengembalikan double> = 0 dan <1. Perhatikan bahwa hal di atas tidak membutuhkan probabilitas yang berjumlah 1; itu menormalkannya untuk Anda.
p hanyalah sebuah fungsi yang menetapkan probabilitas ke item dalam koleksi [awal, akhir). Anda dapat menghilangkannya (atau menggunakan identitas) jika Anda hanya memiliki urutan probabilitas.
sumber
Saya telah menerapkan beberapa algoritma acak tertimbang sederhana .
sumber