Существует простой алгоритм случайного выбора предмета, при котором предметы имеют индивидуальный вес:
1) посчитайте сумму всех весов
2) выберите случайное число, которое равно 0 или больше и меньше суммы весов
3) просматривайте элементы по одному, вычитая их вес из случайного числа, пока не получите элемент, случайное число которого меньше веса этого элемента.
Псевдокод, иллюстрирующий это:
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");
Это должно быть легко адаптировать к вашим буст-контейнерам и тому подобному.
Если ваши веса редко меняются, но вы часто выбираете один случайным образом, и пока ваш контейнер хранит указатели на объекты или имеет длину более нескольких десятков элементов (в основном, вы должны профилировать, чтобы знать, помогает это или мешает) , то идет оптимизация:
Сохраняя сумму совокупного веса в каждом элементе, вы можете использовать двоичный поиск, чтобы выбрать элемент, соответствующий весу выбора.
Если вы не знаете количество элементов в списке, тогда существует очень удобный алгоритм, называемый отбором проб резервуара, который можно адаптировать для взвешивания.
A Monte Carlo method called Russian roulette is used to choose one of these actions
он ищет его в Google, он всплывает группами . «Алгоритм русской рулетки». Вы можете возразить, что у всех этих людей неправильное имя.Обновленный ответ на старый вопрос. Вы можете легко сделать это в C ++ 11 с помощью только std :: lib:
Вывод в моей системе:
Обратите внимание, что большая часть приведенного выше кода посвящена просто отображению и анализу вывода. Фактическая генерация - это всего лишь несколько строк кода. Выходные данные показывают, что запрошенные «вероятности» были получены. Вы должны разделить запрошенный вывод на 1,5, так как это то, к чему складываются запросы.
источник
std::discrete_distribution
вместо того ,std::piecewise_constant_distribution
было бы еще лучше.Если ваши веса изменяются медленнее, чем они нарисованы, C ++ 11
discrete_distribution
будет самым простым:Однако обратите внимание, что c ++ 11
discrete_distribution
вычисляет все совокупные суммы при инициализации. Обычно вам это нужно, потому что это ускоряет время выборки за разовую стоимость O (N). Но для быстро меняющегося дистрибутива это потребует больших затрат на вычисления (и память). Например, если веса представляют количество элементов, и каждый раз, когда вы рисуете один и удаляете его, вам, вероятно, понадобится собственный алгоритм.Ответ Уилла https://stackoverflow.com/a/1761646/837451 позволяет избежать этих накладных расходов, но будет работать медленнее, чем C ++ 11, потому что он не может использовать двоичный поиск.
Чтобы убедиться в этом, вы можете увидеть соответствующие строки (
/usr/include/c++/5/bits/random.tcc
в моей установке Ubuntu 16.04 + GCC 5.3):источник
Когда мне нужно взвесить числа, я использую случайное число для веса.
Например: мне нужно, чтобы сгенерировали случайные числа от 1 до 3 со следующими весами:
Тогда использую:
При этом случайным образом у 10% вероятностей будет 1, 30% - 2 и 60% - 3.
Вы можете играть с ним по своему усмотрению.
Надеюсь, я смогу вам помочь, удачи!
источник
Создайте сумку (или std :: vector) из всех предметов, которые можно выбрать.
Убедитесь, что количество каждого элемента пропорционально вашему весу.
Пример:
Так что имейте мешок со 100 предметами с 60 единицами, 35 двойками и 5 тройками.
Теперь случайным образом отсортируйте сумку (std :: random_shuffle)
Выбирайте элементы из пакета последовательно, пока он не опустеет.
После того, как мешок опустеет, перемешайте его заново и начните заново.
источник
1,2,2
производит 1 1/3 времени и 2 2/3. Произведите случайный выбор массива, выберите первый, скажем, 2, теперь следующий выбранный элемент следует распределению 1 1/2 времени и 2 1/2 времени. Сообразительный?Выберите случайное число на [0,1), которое должно быть оператором по умолчанию () для повышения ГСЧ. Выберите элемент с кумулятивной функцией плотности вероятности> = это число:
Где random01 () возвращает двойное значение> = 0 и <1. Обратите внимание, что приведенное выше не требует суммирования вероятностей до 1; это нормализует их для вас.
p - это просто функция, присваивающая вероятность элементу в коллекции [начало, конец). Вы можете опустить его (или использовать идентификатор), если у вас есть просто последовательность вероятностей.
источник
Я реализовал несколько простых взвешенных случайных алгоритмов .
источник