Методы получения случайных комбинаторных объектов — различия между версиями
Cczy (обсуждение | вклад) |
Cczy (обсуждение | вклад) (→Разбиения на множества) |
||
Строка 75: | Строка 75: | ||
Будем строить разбиение таким образом, чтобы в результате подмножества <tex> \{B_1, B_2, ..., B_k\} </tex> оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых <tex>i, j| 1 \leqslant i < j \leqslant k </tex> наименьший элемент <tex> B_i </tex> был меньше наименьшего элемента <tex> B_i </tex>). Для этого будем по очереди добавлять каждое число от <tex> n </tex> до <tex> 1 </tex> в одно из подмножеств и для каждого из подмножеств начиная с <tex> B_n </tex> и заканчивая <tex> B_1 </tex> будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным). | Будем строить разбиение таким образом, чтобы в результате подмножества <tex> \{B_1, B_2, ..., B_k\} </tex> оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых <tex>i, j| 1 \leqslant i < j \leqslant k </tex> наименьший элемент <tex> B_i </tex> был меньше наименьшего элемента <tex> B_i </tex>). Для этого будем по очереди добавлять каждое число от <tex> n </tex> до <tex> 1 </tex> в одно из подмножеств и для каждого из подмножеств начиная с <tex> B_n </tex> и заканчивая <tex> B_1 </tex> будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным). | ||
− | На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: <tex> l </tex> — число добавленных элементови и <tex> m </tex> — число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заднным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества то есть равно числу разбиений <tex> n-l </tex> элементов на <tex> k-m </tex> непустых подмножеств, что равно <tex dpi = "180">\lbrace{n-l\atop k-m}\rbrace</tex> (т.е [[Числа Стирлинга второго рода|числу Стирлинга второго рода]]). Таким образом из префикса <tex> P </tex> мы можем получить следующий префикс <tex> P' </tex> двумя способами: | + | На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: <tex> l </tex> — число добавленных элементови и <tex> m </tex> — число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заднным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества так, чтобы они оказались лексикографически упорядочены, то есть равно числу разбиений <tex> n-l </tex> элементов на <tex> k-m </tex> непустых подмножеств, что равно <tex dpi = "180">\lbrace{n-l\atop k-m}\rbrace</tex> (т.е [[Числа Стирлинга второго рода|числу Стирлинга второго рода]]). Таким образом из префикса <tex> P </tex> мы можем получить следующий префикс <tex> P' </tex> двумя способами: |
*Добавить текущий элемент (<tex> n-l </tex>) в одно из <tex> k-m </tex> незаполненых подмножеств. В таком случае число обьектов с префиксом <tex> P' </tex> будет равно <tex dpi = "180">\lbrace{n-l-1\atop k-m}\rbrace</tex> . | *Добавить текущий элемент (<tex> n-l </tex>) в одно из <tex> k-m </tex> незаполненых подмножеств. В таком случае число обьектов с префиксом <tex> P' </tex> будет равно <tex dpi = "180">\lbrace{n-l-1\atop k-m}\rbrace</tex> . | ||
− | *Сделать текущий элемент последним в подмножестве <tex> B_{k-m} </tex> . В таком случае это подмножество станет | + | *Сделать текущий элемент последним в подмножестве <tex> B_{k-m} </tex> . В таком случае это подмножество станет законченым, следовательно число обьектов с префиксом <tex> P' </tex> будет равно <tex dpi = "180">\lbrace{n-l-1\atop k-m-1}\rbrace</tex>. |
− | Таким образом на каждом шаге интервал случайных чисел <tex> [0, s] </tex> (где <tex> s = </tex><tex dpi = "180">\lbrace{n-l\atop k-m}\rbrace</tex>) , будет разбиваться на два диапазона размерами <tex dpi = "180">\lbrace{n-l-1\atop k-m-1}\rbrace</tex> и <tex> (k-m)\cdot </tex><tex dpi = "180">\lbrace{n-l-1\atop k-m}\rbrace</tex>. | + | Таким образом на каждом шаге интервал случайных чисел <tex> [0, s] </tex> (где <tex> s = </tex><tex dpi = "180">\lbrace{n-l\atop k-m}\rbrace</tex>) , будет разбиваться на два диапазона размерами <tex dpi = "180">\lbrace{n-l-1\atop k-m-1}\rbrace</tex> и <tex> (k-m)\cdot </tex><tex dpi = "180">\lbrace{n-l-1\atop k-m}\rbrace</tex>. Если случайно сгенерированное число попадет в первый диапазон, то сделаем <tex> n-l </tex> последним элементом в подмножестве <tex> B_{k-m} </tex> . Иначе добавим <tex> n-l </tex> в случайно выбранное из незаконченных подмножеств (<tex> \{B_1, B_2, ..., B_{k-m}\} </tex>). |
Версия 16:56, 8 декабря 2018
Содержание
Описание алгоритма
Задача: |
Необходимо сгенерировать случайный комбинаторный объект размера | с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.
Пусть
- множество различных элементов, которые могут находиться в данном комбинаторном объекте.Будем получать элементы по порядку: сначала определим, какой элемент будет стоять на первом месте, потом на втором и так далее. Считаем, что мы построили префикс длинны
: . Будем выбирать элемент из множества всех возможных так, чтобы вероятность выбора элемнта , была пропорциональна числу комбинторных обьектов размера с префиксом . Для этого разобъем отрезок натуральных чисел . где - число различных комбинаторных объектов с текущим префиксом, на диапазонов так, чтобы размер диапазаоны был равен числу объектов с префиксом . С помощью функция для генерации случайного числа получим число в интервале и добавим к префиксу элемент соответствующий диапазону отрезка в которм находится полученное число.object randomObject(n: int, k: int): //— размер комбинторного объекта, — число различных элемнтов. for i = 1 to n s = number(prefix) // число комбинаторных объектов с текущим префиксом. r = random(1, s) for j = 1 to k if number(prefix + B[j]) < r // — множество всех возможных элементов. r = r - number(prefix + B[j]) // если не попало в текщий диапазон — перейдем к следующему. else prefix[i] = b[j] break return prefix
Сложность алгоритма —
. Количества комбинаторных объектов с заданными префиксами считаются известными, и их подсчет в сложности не учитывается. Стоит отметить, что подсчет количества комбинаторных объектов с заданным префиксом зачастую является задачей с достаточно большой вычислительной сложностью.Доказательство корректности
Докажем по индукции, что вероятность получить любой перфикс
равна , где - число различных комбинаторных данного типа длины , а - число различных комбинаторных обьектов с таким префиксом.- Любой комбинаторный объеут имеет пустой перфикс, следовательно . Вероятность получить любой префикс длины равна , что равно .
- Пусть вероятность получить префикс длины равна
- Тогда вероятность получить из любой префикс длины равна , что равно
Битовые вектора
Рассмотрим алгоритм получения случайного битового вектора. В битовом векторе может находиться только два типа элементов:
и , следовательно . Заметим что для любого префикса длины число возможных комбинаторных объектов одинаково и равно, следовательно на каждом шаге алгоритма небходмо выбирать с равной вероятностью илиvector<int> randomBitVector(n: int): //
— размер битового вектора.
for i = 1 to n
r = random(0, 1)
v[i] = r
return prefix
Сложность алгоритма —
, так как в случае двоичных векторов постоянно и равно .Правильные скобочные последовательности
Рассмотрим алгоритм получения случайной правильной скобочной последовательности. Правильная скобочная пследовательность состоит из двух типов элементов: открывающей и закрывающей скобок, следовательно
.Рассмотрим "полуправильные" скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами:
— длина скобочной последовательности и — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является "полупраильной" скобочной последовательностью, и что для любого префикса длины число различных ПСП длины равно числу "полуправильных" скобочных последовательностей длины с таким же балансом как у .Научимся считать
— число последовательностей длины и баланса ). Если , то ответ понятен сразу: , все остальные . Пусть теперь , тогда переберём, чему мог быть равен последний символ этой последовательности. Если он был равен , то до этого символа мы находились в состоянии . Если он был равен , то предыдущим было состояние . Таким образом, получаем формулу:
(считается, что все значения
при отрицательном равны нулю). Этот преподсчет можно выполнить за .Будем строить префикс следующим образом: на каждом шаге интервал случайных чисел
(где ) , будет разбиваться на два диапазона размерами и , и к префиксу будет прибавляться или если случайное число попало в первый или второй диапазон соответственно.string randomObject(n: int): //
— длина скобочной последовательности.
b = 0
l = 0
for i = 1 to n
s = number[n - l][b]
r = random(1, s)
if number[n - l - 1][b + 1] >= r
l = l + 1
b = b + 1
result = result + '('
else
l = l + 1
b = b - 1
result = result + ')'
return result
Итоговая сложность алгоритма —
на преподсчет.Разбиения на множества
Разбиение на подмножеств
Рассмотрим множество первых
натуральных чисел: . Необходимо разбить его на непустых подмножеств с равным распределением вероятности.Будем строить разбиение таким образом, чтобы в результате подмножества
оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых наименьший элемент был меньше наименьшего элемента ). Для этого будем по очереди добавлять каждое число от до в одно из подмножеств и для каждого из подмножеств начиная с и заканчивая будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным).На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: числу Стирлинга второго рода). Таким образом из префикса мы можем получить следующий префикс двумя способами:
— число добавленных элементови и — число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заднным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества так, чтобы они оказались лексикографически упорядочены, то есть равно числу разбиений элементов на непустых подмножеств, что равно (т.е- Добавить текущий элемент ( ) в одно из незаполненых подмножеств. В таком случае число обьектов с префиксом будет равно .
- Сделать текущий элемент последним в подмножестве . В таком случае это подмножество станет законченым, следовательно число обьектов с префиксом будет равно .
Таким образом на каждом шаге интервал случайных чисел
(где ) , будет разбиваться на два диапазона размерами и . Если случайно сгенерированное число попадет в первый диапазон, то сделаем последним элементом в подмножестве . Иначе добавим в случайно выбранное из незаконченных подмножеств ( ).