<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.66.156.56&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.66.156.56&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/217.66.156.56"/>
		<updated>2026-06-11T14:15:00Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67942</id>
		<title>Методы получения случайных комбинаторных объектов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67942"/>
				<updated>2018-12-16T17:43:43Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.156.56: /* Разбиения на множества */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный [[Комбинаторные объекты|комбинаторный объект]] размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть '''функция для генерации случайного числа в заданном интервале''' (англ. ''random number generator'').&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 \ldots, b_k\} &amp;lt;/tex&amp;gt; {{---}} множество различных элементов, которые могут находиться в данном комбинаторном объекте.&lt;br /&gt;
&lt;br /&gt;
Будем получать элементы по порядку: сначала определим, какой элемент будет стоять на первом месте, потом на втором и так далее. Считаем, что мы построили '''префикс''' (англ. ''prefix'') длинны &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; : &amp;lt;tex&amp;gt; P = \{a_1, a_2, \ldots, a_i\} &amp;lt;/tex&amp;gt;. Будем выбирать элемент &amp;lt;tex&amp;gt; a_{i+1} &amp;lt;/tex&amp;gt; из множества всех возможных так, чтобы вероятность выбора элемнта &amp;lt;tex&amp;gt; b \in B &amp;lt;/tex&amp;gt;, была пропорциональна числу комбинторных обьектов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с префиксом &amp;lt;tex&amp;gt; P + b &amp;lt;/tex&amp;gt;. Для этого разобъем отрезок натуральных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. где &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов с текущим префиксом, на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; диапазонов так, чтобы размер диапазаона &amp;lt;tex&amp;gt; d_j &amp;lt;/tex&amp;gt; был равен числу объектов с  префиксом &amp;lt;tex&amp;gt; P + b_j &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; и добавим к префиксу &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; элемент &amp;lt;tex&amp;gt; b_j &amp;lt;/tex&amp;gt; соответствующий диапазону отрезка в котором находится полученное число.&lt;br /&gt;
&lt;br /&gt;
 '''object''' randomObject(n: '''int''', k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер комбинторного объекта, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число различных элемнтов.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = number(prefix) &amp;lt;font color = green&amp;gt; // число комбинаторных объектов с текущим префиксом. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
     '''for''' j = 1 '''to''' k  &lt;br /&gt;
       '''if''' number(prefix + B[j]) &amp;lt; r &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt; {{---}} множество всех возможных элементов. &amp;lt;/font&amp;gt;&lt;br /&gt;
         r = r - number(prefix + B[j]) &amp;lt;font color = green&amp;gt; // если &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; не попало в текщий диапазон {{---}} перейдем к следующему.&amp;lt;/font&amp;gt;&lt;br /&gt;
       '''else''' &lt;br /&gt;
         prefix[i] = b[j]&lt;br /&gt;
         break&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt;O(nk) &amp;lt;/tex&amp;gt;. Количества комбинаторных объектов с заданными префиксами считаются известными, и их подсчет в сложности не учитывается. Стоит отметить, что подсчет количества комбинаторных объектов с заданным префиксом зачастую является задачей с достаточно большой вычислительной сложностью.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности ==&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=Вероятность получить в процессе работы алгоритма некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C(n) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов данного типа длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt; S(P) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных обьектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с таким префиксом.&lt;br /&gt;
|proof=Докажем по [[Математическая индукция|индукции]]:&lt;br /&gt;
&lt;br /&gt;
'''База:''' Заметим, что любой комбинаторный объект имеет пустой префикс (&amp;lt;tex&amp;gt; \varnothing &amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Вероятность получить некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
\dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
'''Переход:''' Пусть вероятность получить префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;. Вероятность получить из &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; некоторый префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить &lt;br /&gt;
префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; \dfrac{S(P')}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Результатом работы данного алгоритма является случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, причем вероятность получения одинакова для каждого результата.&lt;br /&gt;
|proof=Заметим, что результатом работы данного алгоритма является любой из возможных префиксов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;. Любой такой префикс является комбинаторным объектом размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; и наоборот, следовательно число объектов с таким префиксом равно &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;. Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; \dfrac{1}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Примеры решения задач ==&lt;br /&gt;
Рассмотрим примеры использования данного алгоритма для генерации различных типов комбинаторных объектов.&lt;br /&gt;
&lt;br /&gt;
=== Битовые вектора ===&lt;br /&gt;
Рассмотрим алгоритм получения случайного [[Комбинаторные объекты#Битовые вектора|битового вектора]]. В битовом векторе может находиться только два типа элементов: &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. Заметим что для любого префикса длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число возможных комбинаторных объектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; одинаково и равно &amp;lt;tex&amp;gt; 2^{n-l} &amp;lt;/tex&amp;gt;, следовательно на каждом шаге алгоритма небходмо выбирать с равной вероятностью &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' randomBitVector(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер битового вектора.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     r = random(0, 1)&lt;br /&gt;
     v[i] = r&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, так как в случае двоичных векторов &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; постоянно и равно &amp;lt;tex&amp;gt; 2 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Правильные скобочные последовательности ===&lt;br /&gt;
Рассмотрим алгоритм получения случайной [[Правильные скобочные последовательности|правильной скобочной последовательности]]. Правильная скобочная последовательность состоит  из двух типов элементов: открывающей и закрывающей скобок, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. &lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''Полуправильная скобочная последовательность''' (анлг. ''Semi-correct bracket sequence'') {{---}} скобочная последовательность такая, что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты.&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим полуправильные скобочные последовательности. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — '''баланс''' (англ. ''balance'') {{---}} разность между количеством открывающих и закрывающих скобок. Заметим что любой префикс правильной скобочной последовательности является полуправильной скобочной последовательностью, и что для любого префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число различных правильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; равно числу полуправильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; с таким же балансом как у &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Научимся считать &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; {{---}} число последовательностей длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; и баланса &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt; l = 0 &amp;lt;/tex&amp;gt;, то ответ понятен сразу: &amp;lt;tex&amp;gt; D[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; D[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; l &amp;gt; 0 &amp;lt;/tex&amp;gt;, тогда переберём, чему мог быть равен последний символ этой последовательности. Если он был равен &amp;lt;tex&amp;gt; '(' &amp;lt;/tex&amp;gt;, то до этого символа мы находились в состоянии &amp;lt;tex&amp;gt; (l-1,b-1) &amp;lt;/tex&amp;gt;. Если он был равен &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt;, то предыдущим было состояние &amp;lt;tex&amp;gt;(l-1,b+1)&amp;lt;/tex&amp;gt;. Таким образом, получаем формулу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;D[l][b] = D[l-1][b-1] + D[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; равны нулю). Этот преподсчет можно выполнить за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем строить префикс следующим образом: на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = D[n-l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; D[n-l-1][b+1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D[n-l-1][b-1] &amp;lt;/tex&amp;gt; , и к префиксу будет прибавляться &amp;lt;tex&amp;gt;'('&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt; если случайное число попало в первый или второй диапазон соответственно.&lt;br /&gt;
&lt;br /&gt;
 '''string''' randomBracketSequence(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} длина скобочной последовательности. &amp;lt;/font&amp;gt;&lt;br /&gt;
   b = 0&lt;br /&gt;
   l = 0&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = D[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' D[n - l - 1][b + 1] &amp;gt;= r&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b + 1&lt;br /&gt;
        result = result + '('&lt;br /&gt;
      '''else'''&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b - 1&lt;br /&gt;
        result = result + ')'&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; при условии что &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; известно для любых &amp;lt;tex&amp;gt; l, b \mid l &amp;lt;= n, b &amp;lt;= n &amp;lt;/tex&amp;gt;. Преподсчет &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; можно выполнить динамически за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Разбиения на множества ===&lt;br /&gt;
==== Разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств ====&lt;br /&gt;
Рассмотрим множество первых &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; натуральных чисел: &amp;lt;tex&amp;gt; N_n = \{1, 2, \ldots, n\} &amp;lt;/tex&amp;gt;. Необходимо построить его [[Комбинаторные объекты#Разбиение на подмножества|разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; непустых подмножеств]] &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в '''лексикографическом порядке''' (англ. ''lexicographical order'') (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j \mid 1 \leqslant i &amp;lt; j \leqslant k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_j &amp;lt;/tex&amp;gt;). Для этого будем по очереди добавлять каждое число от &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; в одно из подмножеств и для каждого из подмножеств начиная с &amp;lt;tex&amp;gt; B_n &amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt; B_1 &amp;lt;/tex&amp;gt; будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным). &lt;br /&gt;
&lt;br /&gt;
На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — число добавленных элементов и &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; — число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заданным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества так, чтобы они оказались лексикографически упорядочены, то есть равно числу разбиений &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; непустых подмножеств, что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt; ([[Числа Стирлинга второго рода|числу Стирлинга второго рода]]). Таким образом из префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; мы можем получить следующий префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; двумя способами: &lt;br /&gt;
*Добавить текущий элемент (&amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt;) в одно из &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; незаконченных подмножеств. В таком случае число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
*Сделать текущий элемент последним в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . В таком случае это подмножество станет законченым, следовательно число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Таким образом на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt; &lt;br /&gt;
и &amp;lt;tex&amp;gt; (k-m)\cdot\genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt;. Если случайно сгенерированное число попадет в первый диапазон, то сделаем &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; последним элементом в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . Иначе добавим &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; в случайно выбранное из незаконченных подмножеств (&amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_{k-m}\} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
 '''int[]''' randomSetPartition(n: '''int''' k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''downto''' i = n '''to''' 1                               &lt;br /&gt;
     s = stirling(n - l, k - m) &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; stirling(a, b) &amp;lt;/tex&amp;gt; {{---}} функция возвращающая число Стирлинга второго рода для заданных аргументов. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' stirling(n - l - 1, k - m - 1) &amp;gt;= r&lt;br /&gt;
        result[i] = k - m &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; result[i] &amp;lt;/tex&amp;gt; {{---}} номер подмножества в котором находится элемент &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;. &amp;lt;/font&amp;gt;&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        m = m + 1&lt;br /&gt;
      '''else'''&lt;br /&gt;
        p = random(1, k - m) &amp;lt;font color = green&amp;gt; // Случайным образом выбираем номер одного из незаконченных подмножеств. &amp;lt;/font&amp;gt;&lt;br /&gt;
        result[i] = p&lt;br /&gt;
        l = l + 1&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Так как на каждом шаге интервал случайных чисел разделяется только на на два диапазона, а всего шагов {{---}} &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; то итоговая сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; . Сложность преподсчета чисел Стирлинга второго рода {{---}} &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; если преподсчитать их [[Динамическое программирование | динамически]].&lt;br /&gt;
&lt;br /&gt;
==== Разбиение на случайное число подмножеств ====&lt;br /&gt;
Описаный алгоритм можно применить для получения разбиения множества на случайное число подмножеств. Для этого достаточно случайным образом выбрать число подмножеств из интевала &amp;lt;tex&amp;gt; [1, n] &amp;lt;/tex&amp;gt; , так чтобы вероятность получить число &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; была пропорциональна числу способов разбить &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств (что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{k} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Разделим интервал случайных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;180&amp;quot;&amp;gt; \sum\limits_{i=1}^{n}{\genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i}}&amp;lt;/tex&amp;gt;) на &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; диапазонов, так чтобы размер диапазона &amp;lt;tex&amp;gt; d_i &amp;lt;/tex&amp;gt; был равен&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i} &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. Возьмем &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt; r \in d_k &amp;lt;/tex&amp;gt; и построим случайное разбиение множества из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Метод генерации случайной перестановки, алгоритм Фишера-Йетса|Метод генерации случайной перестановки]]&lt;br /&gt;
*[[Методы генерации случайного сочетания|Методы генерации случайного сочетания]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*Комбинаторные алгоритмы: учебное пособие / Т. И. Федоряева. {{---}} Новосибирск: Новосибирский гос. ун-т, 2011. 118 с. {{---}} ISBN 978-5-4437-0019-9&lt;br /&gt;
*Non-Uniform Random Variate Generation / Luc Devroye. {{---}} Springer, New York, NY, 1986. 843 c. {{---}} ISBN 978-1-4613-8645-2&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Комбинаторика]]&lt;/div&gt;</summary>
		<author><name>217.66.156.56</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67941</id>
		<title>Методы получения случайных комбинаторных объектов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67941"/>
				<updated>2018-12-16T17:36:27Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.156.56: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный [[Комбинаторные объекты|комбинаторный объект]] размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть '''функция для генерации случайного числа в заданном интервале''' (англ. ''random number generator'').&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 \ldots, b_k\} &amp;lt;/tex&amp;gt; {{---}} множество различных элементов, которые могут находиться в данном комбинаторном объекте.&lt;br /&gt;
&lt;br /&gt;
Будем получать элементы по порядку: сначала определим, какой элемент будет стоять на первом месте, потом на втором и так далее. Считаем, что мы построили '''префикс''' (англ. ''prefix'') длинны &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; : &amp;lt;tex&amp;gt; P = \{a_1, a_2, \ldots, a_i\} &amp;lt;/tex&amp;gt;. Будем выбирать элемент &amp;lt;tex&amp;gt; a_{i+1} &amp;lt;/tex&amp;gt; из множества всех возможных так, чтобы вероятность выбора элемнта &amp;lt;tex&amp;gt; b \in B &amp;lt;/tex&amp;gt;, была пропорциональна числу комбинторных обьектов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с префиксом &amp;lt;tex&amp;gt; P + b &amp;lt;/tex&amp;gt;. Для этого разобъем отрезок натуральных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. где &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов с текущим префиксом, на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; диапазонов так, чтобы размер диапазаона &amp;lt;tex&amp;gt; d_j &amp;lt;/tex&amp;gt; был равен числу объектов с  префиксом &amp;lt;tex&amp;gt; P + b_j &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; и добавим к префиксу &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; элемент &amp;lt;tex&amp;gt; b_j &amp;lt;/tex&amp;gt; соответствующий диапазону отрезка в котором находится полученное число.&lt;br /&gt;
&lt;br /&gt;
 '''object''' randomObject(n: '''int''', k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер комбинторного объекта, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число различных элемнтов.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = number(prefix) &amp;lt;font color = green&amp;gt; // число комбинаторных объектов с текущим префиксом. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
     '''for''' j = 1 '''to''' k  &lt;br /&gt;
       '''if''' number(prefix + B[j]) &amp;lt; r &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt; {{---}} множество всех возможных элементов. &amp;lt;/font&amp;gt;&lt;br /&gt;
         r = r - number(prefix + B[j]) &amp;lt;font color = green&amp;gt; // если &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; не попало в текщий диапазон {{---}} перейдем к следующему.&amp;lt;/font&amp;gt;&lt;br /&gt;
       '''else''' &lt;br /&gt;
         prefix[i] = b[j]&lt;br /&gt;
         break&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt;O(nk) &amp;lt;/tex&amp;gt;. Количества комбинаторных объектов с заданными префиксами считаются известными, и их подсчет в сложности не учитывается. Стоит отметить, что подсчет количества комбинаторных объектов с заданным префиксом зачастую является задачей с достаточно большой вычислительной сложностью.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности ==&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=Вероятность получить в процессе работы алгоритма некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C(n) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов данного типа длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt; S(P) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных обьектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с таким префиксом.&lt;br /&gt;
|proof=Докажем по [[Математическая индукция|индукции]]:&lt;br /&gt;
&lt;br /&gt;
'''База:''' Заметим, что любой комбинаторный объект имеет пустой префикс (&amp;lt;tex&amp;gt; \varnothing &amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Вероятность получить некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
\dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
'''Переход:''' Пусть вероятность получить префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;. Вероятность получить из &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; некоторый префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить &lt;br /&gt;
префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; \dfrac{S(P')}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Результатом работы данного алгоритма является случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, причем вероятность получения одинакова для каждого результата.&lt;br /&gt;
|proof=Заметим, что результатом работы данного алгоритма является любой из возможных префиксов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;. Любой такой префикс является комбинаторным объектом размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; и наоборот, следовательно число объектов с таким префиксом равно &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;. Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; \dfrac{1}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Примеры решения задач ==&lt;br /&gt;
Рассмотрим примеры использования данного алгоритма для генерации различных типов комбинаторных объектов.&lt;br /&gt;
&lt;br /&gt;
=== Битовые вектора ===&lt;br /&gt;
Рассмотрим алгоритм получения случайного [[Комбинаторные объекты#Битовые вектора|битового вектора]]. В битовом векторе может находиться только два типа элементов: &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. Заметим что для любого префикса длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число возможных комбинаторных объектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; одинаково и равно &amp;lt;tex&amp;gt; 2^{n-l} &amp;lt;/tex&amp;gt;, следовательно на каждом шаге алгоритма небходмо выбирать с равной вероятностью &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' randomBitVector(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер битового вектора.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     r = random(0, 1)&lt;br /&gt;
     v[i] = r&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, так как в случае двоичных векторов &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; постоянно и равно &amp;lt;tex&amp;gt; 2 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Правильные скобочные последовательности ===&lt;br /&gt;
Рассмотрим алгоритм получения случайной [[Правильные скобочные последовательности|правильной скобочной последовательности]]. Правильная скобочная последовательность состоит  из двух типов элементов: открывающей и закрывающей скобок, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. &lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''Полуправильная скобочная последовательность''' (анлг. ''Semi-correct bracket sequence'') {{---}} скобочная последовательность такая, что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты.&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим полуправильные скобочные последовательности. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — '''баланс''' (англ. ''balance'') {{---}} разность между количеством открывающих и закрывающих скобок. Заметим что любой префикс правильной скобочной последовательности является полуправильной скобочной последовательностью, и что для любого префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число различных правильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; равно числу полуправильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; с таким же балансом как у &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Научимся считать &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; {{---}} число последовательностей длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; и баланса &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt; l = 0 &amp;lt;/tex&amp;gt;, то ответ понятен сразу: &amp;lt;tex&amp;gt; D[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; D[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; l &amp;gt; 0 &amp;lt;/tex&amp;gt;, тогда переберём, чему мог быть равен последний символ этой последовательности. Если он был равен &amp;lt;tex&amp;gt; '(' &amp;lt;/tex&amp;gt;, то до этого символа мы находились в состоянии &amp;lt;tex&amp;gt; (l-1,b-1) &amp;lt;/tex&amp;gt;. Если он был равен &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt;, то предыдущим было состояние &amp;lt;tex&amp;gt;(l-1,b+1)&amp;lt;/tex&amp;gt;. Таким образом, получаем формулу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;D[l][b] = D[l-1][b-1] + D[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; равны нулю). Этот преподсчет можно выполнить за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем строить префикс следующим образом: на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = D[n-l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; D[n-l-1][b+1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D[n-l-1][b-1] &amp;lt;/tex&amp;gt; , и к префиксу будет прибавляться &amp;lt;tex&amp;gt;'('&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt; если случайное число попало в первый или второй диапазон соответственно.&lt;br /&gt;
&lt;br /&gt;
 '''string''' randomBracketSequence(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} длина скобочной последовательности. &amp;lt;/font&amp;gt;&lt;br /&gt;
   b = 0&lt;br /&gt;
   l = 0&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = D[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' D[n - l - 1][b + 1] &amp;gt;= r&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b + 1&lt;br /&gt;
        result = result + '('&lt;br /&gt;
      '''else'''&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b - 1&lt;br /&gt;
        result = result + ')'&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; при условии что &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; известно для любых &amp;lt;tex&amp;gt; l, b \mid l &amp;lt;= n, b &amp;lt;= n &amp;lt;/tex&amp;gt;. Преподсчет &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; можно выполнить динамически за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Разбиения на множества ===&lt;br /&gt;
==== Разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств ====&lt;br /&gt;
Рассмотрим множество первых &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; натуральных чисел: &amp;lt;tex&amp;gt; N_n = \{1, 2, \ldots, n\} &amp;lt;/tex&amp;gt;. Необходимо построить его [[Комбинаторные объекты#Разбиение на подмножества|разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; непустых подмножеств]] &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j \mid 1 \leqslant i &amp;lt; j \leqslant k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_j &amp;lt;/tex&amp;gt;). Для этого будем по очереди добавлять каждое число от &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; в одно из подмножеств и для каждого из подмножеств начиная с &amp;lt;tex&amp;gt; B_n &amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt; B_1 &amp;lt;/tex&amp;gt; будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным). &lt;br /&gt;
&lt;br /&gt;
На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — число добавленных элементов и &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; — число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заданным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества так, чтобы они оказались лексикографически упорядочены, то есть равно числу разбиений &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; непустых подмножеств, что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt; ([[Числа Стирлинга второго рода|числу Стирлинга второго рода]]). Таким образом из префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; мы можем получить следующий префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; двумя способами: &lt;br /&gt;
*Добавить текущий элемент (&amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt;) в одно из &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; незаконченных подмножеств. В таком случае число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
*Сделать текущий элемент последним в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . В таком случае это подмножество станет законченым, следовательно число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Таким образом на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt; &lt;br /&gt;
и &amp;lt;tex&amp;gt; (k-m)\cdot\genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt;. Если случайно сгенерированное число попадет в первый диапазон, то сделаем &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; последним элементом в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . Иначе добавим &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; в случайно выбранное из незаконченных подмножеств (&amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_{k-m}\} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
 '''int[]''' randomSetPartition(n: '''int''' k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''downto''' i = n '''to''' 1                               &lt;br /&gt;
     s = stirling(n - l, k - m) &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; stirling(a, b) &amp;lt;/tex&amp;gt; {{---}} функция возвращающая число Стирлинга второго рода для заданных аргументов. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' stirling(n - l - 1, k - m - 1) &amp;gt;= r&lt;br /&gt;
        result[i] = k - m &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; result[i] &amp;lt;/tex&amp;gt; {{---}} номер подмножества в котором находится элемент &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;. &amp;lt;/font&amp;gt;&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        m = m + 1&lt;br /&gt;
      '''else'''&lt;br /&gt;
        p = random(1, k - m) &amp;lt;font color = green&amp;gt; // Случайным образом выбираем номер одного из незаконченных подмножеств. &amp;lt;/font&amp;gt;&lt;br /&gt;
        result[i] = p&lt;br /&gt;
        l = l + 1&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Так как на каждом шаге интервал случайных чисел разделяется только на на два диапазона, а всего шагов {{---}} &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; то итоговая сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; . Сложность преподсчета чисел Стирлинга второго рода {{---}} &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; если преподсчитать их [[Динамическое программирование | динамически]].&lt;br /&gt;
&lt;br /&gt;
==== Разбиение на случайное число подмножеств ====&lt;br /&gt;
Описаный алгоритм можно применить для получения разбиения множества на случайное число подмножеств. Для этого достаточно случайным образом выбрать число подмножеств из интевала &amp;lt;tex&amp;gt; [1, n] &amp;lt;/tex&amp;gt; , так чтобы вероятность получить число &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; была пропорциональна числу способов разбить &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств (что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{k} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Разделим интервал случайных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;180&amp;quot;&amp;gt; \sum\limits_{i=1}^{n}{\genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i}}&amp;lt;/tex&amp;gt;) на &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; диапазонов, так чтобы размер диапазона &amp;lt;tex&amp;gt; d_i &amp;lt;/tex&amp;gt; был равен&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i} &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. Возьмем &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt; r \in d_k &amp;lt;/tex&amp;gt; и построим случайное разбиение множества из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Метод генерации случайной перестановки, алгоритм Фишера-Йетса|Метод генерации случайной перестановки]]&lt;br /&gt;
*[[Методы генерации случайного сочетания|Методы генерации случайного сочетания]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*Комбинаторные алгоритмы: учебное пособие / Т. И. Федоряева. {{---}} Новосибирск: Новосибирский гос. ун-т, 2011. 118 с. {{---}} ISBN 978-5-4437-0019-9&lt;br /&gt;
*Non-Uniform Random Variate Generation / Luc Devroye. {{---}} Springer, New York, NY, 1986. 843 c. {{---}} ISBN 978-1-4613-8645-2&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Комбинаторика]]&lt;/div&gt;</summary>
		<author><name>217.66.156.56</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67940</id>
		<title>Методы получения случайных комбинаторных объектов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67940"/>
				<updated>2018-12-16T17:05:37Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.156.56: /* Примеры решения задач */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный [[Комбинаторные объекты|комбинаторный объект]] размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 \ldots, b_k\} &amp;lt;/tex&amp;gt; {{---}} множество различных элементов, которые могут находиться в данном комбинаторном объекте.&lt;br /&gt;
&lt;br /&gt;
Будем получать элементы по порядку: сначала определим, какой элемент будет стоять на первом месте, потом на втором и так далее. Считаем, что мы построили префикс длинны &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; : &amp;lt;tex&amp;gt; P = \{a_1, a_2, \ldots, a_i\} &amp;lt;/tex&amp;gt;. Будем выбирать элемент &amp;lt;tex&amp;gt; a_{i+1} &amp;lt;/tex&amp;gt; из множества всех возможных так, чтобы вероятность выбора элемнта &amp;lt;tex&amp;gt; b \in B &amp;lt;/tex&amp;gt;, была пропорциональна числу комбинторных обьектов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с префиксом &amp;lt;tex&amp;gt; P + b &amp;lt;/tex&amp;gt;. Для этого разобъем отрезок натуральных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. где &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов с текущим префиксом, на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; диапазонов так, чтобы размер диапазаона &amp;lt;tex&amp;gt; d_j &amp;lt;/tex&amp;gt; был равен числу объектов с  префиксом &amp;lt;tex&amp;gt; P + b_j &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; и добавим к префиксу &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; элемент &amp;lt;tex&amp;gt; b_j &amp;lt;/tex&amp;gt; соответствующий диапазону отрезка в котором находится полученное число.&lt;br /&gt;
&lt;br /&gt;
 '''object''' randomObject(n: '''int''', k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер комбинторного объекта, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число различных элемнтов.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = number(prefix) &amp;lt;font color = green&amp;gt; // число комбинаторных объектов с текущим префиксом. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
     '''for''' j = 1 '''to''' k  &lt;br /&gt;
       '''if''' number(prefix + B[j]) &amp;lt; r &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt; {{---}} множество всех возможных элементов. &amp;lt;/font&amp;gt;&lt;br /&gt;
         r = r - number(prefix + B[j]) &amp;lt;font color = green&amp;gt; // если &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; не попало в текщий диапазон {{---}} перейдем к следующему.&amp;lt;/font&amp;gt;&lt;br /&gt;
       '''else''' &lt;br /&gt;
         prefix[i] = b[j]&lt;br /&gt;
         break&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt;O(nk) &amp;lt;/tex&amp;gt;. Количества комбинаторных объектов с заданными префиксами считаются известными, и их подсчет в сложности не учитывается. Стоит отметить, что подсчет количества комбинаторных объектов с заданным префиксом зачастую является задачей с достаточно большой вычислительной сложностью.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности ==&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=Вероятность получить в процессе работы алгоритма некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C(n) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов данного типа длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt; S(P) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных обьектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с таким префиксом.&lt;br /&gt;
|proof=Докажем по [[Математическая индукция|индукции]]:&lt;br /&gt;
&lt;br /&gt;
'''База:''' Заметим, что любой комбинаторный объект имеет пустой префикс (&amp;lt;tex&amp;gt; \varnothing &amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Вероятность получить некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
\dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
'''Переход:''' Пусть вероятность получить префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;. Вероятность получить из &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; некоторый префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить &lt;br /&gt;
префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; \dfrac{S(P')}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Результатом работы данного алгоритма является случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, причем вероятность получения одинакова для каждого результата.&lt;br /&gt;
|proof=Заметим, что результатом работы данного алгоритма является любой из возможных префиксов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;. Любой такой префикс является комбинаторным объектом размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; и наоборот, следовательно число объектов с таким префиксом равно &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;. Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; \dfrac{1}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Примеры решения задач ==&lt;br /&gt;
Рассмотрим примеры использования данного алгоритма для генерации различных типов комбинаторных объектов.&lt;br /&gt;
&lt;br /&gt;
=== Битовые вектора ===&lt;br /&gt;
Рассмотрим алгоритм получения случайного [[Комбинаторные объекты#Битовые вектора|битового вектора]] (англ. ''Bit Vector''). В битовом векторе может находиться только два типа элементов: &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. Заметим что для любого префикса длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число возможных комбинаторных объектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; одинаково и равно &amp;lt;tex&amp;gt; 2^{n-l} &amp;lt;/tex&amp;gt;, следовательно на каждом шаге алгоритма небходмо выбирать с равной вероятностью &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' randomBitVector(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер битового вектора.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     r = random(0, 1)&lt;br /&gt;
     v[i] = r&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, так как в случае двоичных векторов &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; постоянно и равно &amp;lt;tex&amp;gt; 2 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Правильные скобочные последовательности ===&lt;br /&gt;
Рассмотрим алгоритм получения случайной [[Правильные скобочные последовательности|правильной скобочной последовательности]] (анлг. ''Correct Bracket Sequence''). Правильная скобочная последовательность состоит  из двух типов элементов: открывающей и закрывающей скобок, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. &lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''Полуправильная скобочная последовательность''' (анлг. ''Semi-Correct Bracket Sequence'') {{---}} скобочная последовательность такая, что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты.&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим полуправильные скобочные последовательности. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является полуправильной скобочной последовательностью, и что для любого префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число различных правильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; равно числу полуправильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; с таким же балансом как у &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Научимся считать &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; {{---}} число последовательностей длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; и баланса &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt; l = 0 &amp;lt;/tex&amp;gt;, то ответ понятен сразу: &amp;lt;tex&amp;gt; D[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; D[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; l &amp;gt; 0 &amp;lt;/tex&amp;gt;, тогда переберём, чему мог быть равен последний символ этой последовательности. Если он был равен &amp;lt;tex&amp;gt; '(' &amp;lt;/tex&amp;gt;, то до этого символа мы находились в состоянии &amp;lt;tex&amp;gt; (l-1,b-1) &amp;lt;/tex&amp;gt;. Если он был равен &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt;, то предыдущим было состояние &amp;lt;tex&amp;gt;(l-1,b+1)&amp;lt;/tex&amp;gt;. Таким образом, получаем формулу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;D[l][b] = D[l-1][b-1] + D[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; равны нулю). Этот преподсчет можно выполнить за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем строить префикс следующим образом: на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = D[n-l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; D[n-l-1][b+1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D[n-l-1][b-1] &amp;lt;/tex&amp;gt; , и к префиксу будет прибавляться &amp;lt;tex&amp;gt;'('&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt; если случайное число попало в первый или второй диапазон соответственно.&lt;br /&gt;
&lt;br /&gt;
 '''string''' randomBracketSequence(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} длина скобочной последовательности. &amp;lt;/font&amp;gt;&lt;br /&gt;
   b = 0&lt;br /&gt;
   l = 0&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = D[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' D[n - l - 1][b + 1] &amp;gt;= r&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b + 1&lt;br /&gt;
        result = result + '('&lt;br /&gt;
      '''else'''&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b - 1&lt;br /&gt;
        result = result + ')'&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; при условии что &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; известно для любых &amp;lt;tex&amp;gt; l, b \mid l &amp;lt;= n, b &amp;lt;= n &amp;lt;/tex&amp;gt;. Преподсчет &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; можно выполнить динамически за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Разбиения на множества ===&lt;br /&gt;
==== Разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств ====&lt;br /&gt;
Рассмотрим множество первых &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; натуральных чисел: &amp;lt;tex&amp;gt; N_n = \{1, 2, \ldots, n\} &amp;lt;/tex&amp;gt;. Необходимо построить его [[Комбинаторные объекты#Разбиение на подмножества|разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; непустых подмножеств]] (анлг. ''Set Partition'') &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j \mid 1 \leqslant i &amp;lt; j \leqslant k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_j &amp;lt;/tex&amp;gt;). Для этого будем по очереди добавлять каждое число от &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; в одно из подмножеств и для каждого из подмножеств начиная с &amp;lt;tex&amp;gt; B_n &amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt; B_1 &amp;lt;/tex&amp;gt; будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным). &lt;br /&gt;
&lt;br /&gt;
На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — число добавленных элементов и &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; — число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заданным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества так, чтобы они оказались лексикографически упорядочены, то есть равно числу разбиений &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; непустых подмножеств, что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt; ([[Числа Стирлинга второго рода|числу Стирлинга второго рода]]). Таким образом из префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; мы можем получить следующий префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; двумя способами: &lt;br /&gt;
*Добавить текущий элемент (&amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt;) в одно из &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; незаконченных подмножеств. В таком случае число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
*Сделать текущий элемент последним в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . В таком случае это подмножество станет законченым, следовательно число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Таким образом на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt; &lt;br /&gt;
и &amp;lt;tex&amp;gt; (k-m)\cdot\genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt;. Если случайно сгенерированное число попадет в первый диапазон, то сделаем &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; последним элементом в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . Иначе добавим &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; в случайно выбранное из незаконченных подмножеств (&amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_{k-m}\} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
 '''int[]''' randomSetPartition(n: '''int''' k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''downto''' i = n '''to''' 1                               &lt;br /&gt;
     s = stirling(n - l, k - m) &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; stirling(a, b) &amp;lt;/tex&amp;gt; {{---}} функция возвращающая число Стирлинга второго рода для заданных аргументов. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' stirling(n - l - 1, k - m - 1) &amp;gt;= r&lt;br /&gt;
        result[i] = k - m &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; result[i] &amp;lt;/tex&amp;gt; {{---}} номер подмножества в котором находится элемент &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;. &amp;lt;/font&amp;gt;&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        m = m + 1&lt;br /&gt;
      '''else'''&lt;br /&gt;
        p = random(1, k - m) &amp;lt;font color = green&amp;gt; // Случайным образом выбираем номер одного из незаконченных подмножеств. &amp;lt;/font&amp;gt;&lt;br /&gt;
        result[i] = p&lt;br /&gt;
        l = l + 1&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Так как на каждом шаге интервал случайных чисел разделяется только на на два диапазона, а всего шагов {{---}} &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; то итоговая сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; . Сложность преподсчета чисел Стирлинга второго рода {{---}} &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; если преподсчитать их [[Динамическое программирование | динамически]].&lt;br /&gt;
&lt;br /&gt;
==== Разбиение на случайное число подмножеств ====&lt;br /&gt;
Описаный алгоритм можно применить для получения разбиения множества на случайное число подмножеств. Для этого достаточно случайным образом выбрать число подмножеств из интевала &amp;lt;tex&amp;gt; [1, n] &amp;lt;/tex&amp;gt; , так чтобы вероятность получить число &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; была пропорциональна числу способов разбить &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств (что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{k} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Разделим интервал случайных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;180&amp;quot;&amp;gt; \sum\limits_{i=1}^{n}{\genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i}}&amp;lt;/tex&amp;gt;) на &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; диапазонов, так чтобы размер диапазона &amp;lt;tex&amp;gt; d_i &amp;lt;/tex&amp;gt; был равен&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i} &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. Возьмем &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt; r \in d_k &amp;lt;/tex&amp;gt; и построим случайное разбиение множества из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Метод генерации случайной перестановки, алгоритм Фишера-Йетса|Метод генерации случайной перестановки]]&lt;br /&gt;
*[[Методы генерации случайного сочетания|Методы генерации случайного сочетания]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*Комбинаторные алгоритмы: учебное пособие / Т. И. Федоряева. {{---}} Новосибирск: Новосибирский гос. ун-т, 2011. 118 с. {{---}} ISBN 978-5-4437-0019-9&lt;br /&gt;
*Non-Uniform Random Variate Generation / Luc Devroye. {{---}} Springer, New York, NY, 1986. 843 c. {{---}} ISBN 978-1-4613-8645-2&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Комбинаторика]]&lt;/div&gt;</summary>
		<author><name>217.66.156.56</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67939</id>
		<title>Методы получения случайных комбинаторных объектов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67939"/>
				<updated>2018-12-16T16:55:12Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.156.56: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный [[Комбинаторные объекты|комбинаторный объект]] размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 \ldots, b_k\} &amp;lt;/tex&amp;gt; {{---}} множество различных элементов, которые могут находиться в данном комбинаторном объекте.&lt;br /&gt;
&lt;br /&gt;
Будем получать элементы по порядку: сначала определим, какой элемент будет стоять на первом месте, потом на втором и так далее. Считаем, что мы построили префикс длинны &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; : &amp;lt;tex&amp;gt; P = \{a_1, a_2, \ldots, a_i\} &amp;lt;/tex&amp;gt;. Будем выбирать элемент &amp;lt;tex&amp;gt; a_{i+1} &amp;lt;/tex&amp;gt; из множества всех возможных так, чтобы вероятность выбора элемнта &amp;lt;tex&amp;gt; b \in B &amp;lt;/tex&amp;gt;, была пропорциональна числу комбинторных обьектов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с префиксом &amp;lt;tex&amp;gt; P + b &amp;lt;/tex&amp;gt;. Для этого разобъем отрезок натуральных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. где &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов с текущим префиксом, на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; диапазонов так, чтобы размер диапазаона &amp;lt;tex&amp;gt; d_j &amp;lt;/tex&amp;gt; был равен числу объектов с  префиксом &amp;lt;tex&amp;gt; P + b_j &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; и добавим к префиксу &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; элемент &amp;lt;tex&amp;gt; b_j &amp;lt;/tex&amp;gt; соответствующий диапазону отрезка в котором находится полученное число.&lt;br /&gt;
&lt;br /&gt;
 '''object''' randomObject(n: '''int''', k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер комбинторного объекта, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число различных элемнтов.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = number(prefix) &amp;lt;font color = green&amp;gt; // число комбинаторных объектов с текущим префиксом. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
     '''for''' j = 1 '''to''' k  &lt;br /&gt;
       '''if''' number(prefix + B[j]) &amp;lt; r &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt; {{---}} множество всех возможных элементов. &amp;lt;/font&amp;gt;&lt;br /&gt;
         r = r - number(prefix + B[j]) &amp;lt;font color = green&amp;gt; // если &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; не попало в текщий диапазон {{---}} перейдем к следующему.&amp;lt;/font&amp;gt;&lt;br /&gt;
       '''else''' &lt;br /&gt;
         prefix[i] = b[j]&lt;br /&gt;
         break&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt;O(nk) &amp;lt;/tex&amp;gt;. Количества комбинаторных объектов с заданными префиксами считаются известными, и их подсчет в сложности не учитывается. Стоит отметить, что подсчет количества комбинаторных объектов с заданным префиксом зачастую является задачей с достаточно большой вычислительной сложностью.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности ==&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=Вероятность получить в процессе работы алгоритма некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C(n) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов данного типа длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt; S(P) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных обьектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с таким префиксом.&lt;br /&gt;
|proof=Докажем по [[Математическая индукция|индукции]]:&lt;br /&gt;
&lt;br /&gt;
'''База:''' Заметим, что любой комбинаторный объект имеет пустой префикс (&amp;lt;tex&amp;gt; \varnothing &amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Вероятность получить некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
\dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
'''Переход:''' Пусть вероятность получить префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;. Вероятность получить из &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; некоторый префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить &lt;br /&gt;
префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; \dfrac{S(P')}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Результатом работы данного алгоритма является случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, причем вероятность получения одинакова для каждого результата.&lt;br /&gt;
|proof=Заметим, что результатом работы данного алгоритма является любой из возможных префиксов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;. Любой такой префикс является комбинаторным объектом размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; и наоборот, следовательно число объектов с таким префиксом равно &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;. Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; \dfrac{1}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Примеры решения задач ==&lt;br /&gt;
Рассмотрим примеры использования данного алгоритма для генерации различных типов комбинаторных объектов.&lt;br /&gt;
&lt;br /&gt;
=== Битовые вектора ===&lt;br /&gt;
Рассмотрим алгоритм получения случайного [[Комбинаторные объекты#Битовые вектора|битового вектора]]. В битовом векторе может находиться только два типа элементов: &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. Заметим что для любого префикса длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число возможных комбинаторных объектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; одинаково и равно &amp;lt;tex&amp;gt; 2^{n-l} &amp;lt;/tex&amp;gt;, следовательно на каждом шаге алгоритма небходмо выбирать с равной вероятностью &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' randomBitVector(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер битового вектора.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     r = random(0, 1)&lt;br /&gt;
     v[i] = r&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, так как в случае двоичных векторов &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; постоянно и равно &amp;lt;tex&amp;gt; 2 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Правильные скобочные последовательности ===&lt;br /&gt;
Рассмотрим алгоритм получения случайной [[Правильные скобочные последовательности|правильной скобочной последовательности]]. Правильная скобочная последовательность состоит  из двух типов элементов: открывающей и закрывающей скобок, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. &lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''Полуправильная скобочная последовательность''' {{---}} скобочная последовательность такая, что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты.&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим полуправильные скобочные последовательности. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является полуправильной скобочной последовательностью, и что для любого префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число различных правильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; равно числу полуправильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; с таким же балансом как у &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Научимся считать &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; {{---}} число последовательностей длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; и баланса &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt; l = 0 &amp;lt;/tex&amp;gt;, то ответ понятен сразу: &amp;lt;tex&amp;gt; D[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; D[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; l &amp;gt; 0 &amp;lt;/tex&amp;gt;, тогда переберём, чему мог быть равен последний символ этой последовательности. Если он был равен &amp;lt;tex&amp;gt; '(' &amp;lt;/tex&amp;gt;, то до этого символа мы находились в состоянии &amp;lt;tex&amp;gt; (l-1,b-1) &amp;lt;/tex&amp;gt;. Если он был равен &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt;, то предыдущим было состояние &amp;lt;tex&amp;gt;(l-1,b+1)&amp;lt;/tex&amp;gt;. Таким образом, получаем формулу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;D[l][b] = D[l-1][b-1] + D[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; равны нулю). Этот преподсчет можно выполнить за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем строить префикс следующим образом: на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = D[n-l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; D[n-l-1][b+1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D[n-l-1][b-1] &amp;lt;/tex&amp;gt; , и к префиксу будет прибавляться &amp;lt;tex&amp;gt;'('&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt; если случайное число попало в первый или второй диапазон соответственно.&lt;br /&gt;
&lt;br /&gt;
 '''string''' randomBracketSequence(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} длина скобочной последовательности. &amp;lt;/font&amp;gt;&lt;br /&gt;
   b = 0&lt;br /&gt;
   l = 0&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = D[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' D[n - l - 1][b + 1] &amp;gt;= r&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b + 1&lt;br /&gt;
        result = result + '('&lt;br /&gt;
      '''else'''&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b - 1&lt;br /&gt;
        result = result + ')'&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; при условии что &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; известно для любых &amp;lt;tex&amp;gt; l, b \mid l &amp;lt;= n, b &amp;lt;= n &amp;lt;/tex&amp;gt;. Преподсчет &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; можно выполнить динамически за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Разбиения на множества ===&lt;br /&gt;
==== Разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств ====&lt;br /&gt;
Рассмотрим множество первых &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; натуральных чисел: &amp;lt;tex&amp;gt; N_n = \{1, 2, \ldots, n\} &amp;lt;/tex&amp;gt;. Необходимо [[Комбинаторные объекты#Разбиение на подмножества|разбить]] его на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; непустых подмножеств &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j \mid 1 \leqslant i &amp;lt; j \leqslant k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_j &amp;lt;/tex&amp;gt;). Для этого будем по очереди добавлять каждое число от &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; в одно из подмножеств и для каждого из подмножеств начиная с &amp;lt;tex&amp;gt; B_n &amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt; B_1 &amp;lt;/tex&amp;gt; будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным). &lt;br /&gt;
&lt;br /&gt;
На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — число добавленных элементов и &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; — число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заданным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества так, чтобы они оказались лексикографически упорядочены, то есть равно числу разбиений &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; непустых подмножеств, что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt; ([[Числа Стирлинга второго рода|числу Стирлинга второго рода]]). Таким образом из префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; мы можем получить следующий префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; двумя способами: &lt;br /&gt;
*Добавить текущий элемент (&amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt;) в одно из &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; незаконченных подмножеств. В таком случае число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
*Сделать текущий элемент последним в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . В таком случае это подмножество станет законченым, следовательно число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Таким образом на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt; &lt;br /&gt;
и &amp;lt;tex&amp;gt; (k-m)\cdot\genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt;. Если случайно сгенерированное число попадет в первый диапазон, то сделаем &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; последним элементом в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . Иначе добавим &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; в случайно выбранное из незаконченных подмножеств (&amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_{k-m}\} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
 '''int[]''' randomSetPartition(n: '''int''' k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''downto''' i = n '''to''' 1                               &lt;br /&gt;
     s = stirling(n - l, k - m) &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; stirling(a, b) &amp;lt;/tex&amp;gt; {{---}} функция возвращающая число Стирлинга второго рода для заданных аргументов. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' stirling(n - l - 1, k - m - 1) &amp;gt;= r&lt;br /&gt;
        result[i] = k - m &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; result[i] &amp;lt;/tex&amp;gt; {{---}} номер подмножества в котором находится элемент &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;. &amp;lt;/font&amp;gt;&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        m = m + 1&lt;br /&gt;
      '''else'''&lt;br /&gt;
        p = random(1, k - m) &amp;lt;font color = green&amp;gt; // Случайным образом выбираем номер одного из незаконченных подмножеств. &amp;lt;/font&amp;gt;&lt;br /&gt;
        result[i] = p&lt;br /&gt;
        l = l + 1&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Так как на каждом шаге интервал случайных чисел разделяется только на на два диапазона, а всего шагов {{---}} &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; то итоговая сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; . Сложность преподсчета чисел Стирлинга второго рода {{---}} &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; если преподсчитать их [[Динамическое программирование | динамически]].&lt;br /&gt;
&lt;br /&gt;
==== Разбиение на случайное число подмножеств ====&lt;br /&gt;
Описаный алгоритм можно применить для получения разбиения множества на случайное число подмножеств. Для этого достаточно случайным образом выбрать число подмножеств из интевала &amp;lt;tex&amp;gt; [1, n] &amp;lt;/tex&amp;gt; , так чтобы вероятность получить число &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; была пропорциональна числу способов разбить &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств (что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{k} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Разделим интервал случайных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;180&amp;quot;&amp;gt; \sum\limits_{i=1}^{n}{\genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i}}&amp;lt;/tex&amp;gt;) на &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; диапазонов, так чтобы размер диапазона &amp;lt;tex&amp;gt; d_i &amp;lt;/tex&amp;gt; был равен&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i} &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. Возьмем &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt; r \in d_k &amp;lt;/tex&amp;gt; и построим случайное разбиение множества из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Метод генерации случайной перестановки, алгоритм Фишера-Йетса|Метод генерации случайной перестановки]]&lt;br /&gt;
*[[Методы генерации случайного сочетания|Методы генерации случайного сочетания]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*Комбинаторные алгоритмы: учебное пособие / Т. И. Федоряева. {{---}} Новосибирск: Новосибирский гос. ун-т, 2011. 118 с. {{---}} ISBN 978-5-4437-0019-9&lt;br /&gt;
*Non-Uniform Random Variate Generation / Luc Devroye. {{---}} Springer, New York, NY, 1986. 843 c. {{---}} ISBN 978-1-4613-8645-2&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Комбинаторика]]&lt;/div&gt;</summary>
		<author><name>217.66.156.56</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67937</id>
		<title>Методы получения случайных комбинаторных объектов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67937"/>
				<updated>2018-12-16T11:49:31Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.156.56: /* Правильные скобочные последовательности */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = '''[[Комбинаторные объекты]]''' (англ. ''combinatorial objects'') {{---}} конечные множества, на элементы которых могут накладываться определённые ограничения, такие как: различимость или неразличимость элементов, возможность повторения одинаковых элементов и т. п.}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 \ldots, b_k\} &amp;lt;/tex&amp;gt; {{---}} множество различных элементов, которые могут находиться в данном комбинаторном объекте.&lt;br /&gt;
&lt;br /&gt;
Будем получать элементы по порядку: сначала определим, какой элемент будет стоять на первом месте, потом на втором и так далее. Считаем, что мы построили префикс длинны &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; : &amp;lt;tex&amp;gt; P = \{a_1, a_2, \ldots, a_i\} &amp;lt;/tex&amp;gt;. Будем выбирать элемент &amp;lt;tex&amp;gt; a_{i+1} &amp;lt;/tex&amp;gt; из множества всех возможных так, чтобы вероятность выбора элемнта &amp;lt;tex&amp;gt; b \in B &amp;lt;/tex&amp;gt;, была пропорциональна числу комбинторных обьектов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с префиксом &amp;lt;tex&amp;gt; P + b &amp;lt;/tex&amp;gt;. Для этого разобъем отрезок натуральных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. где &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов с текущим префиксом, на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; диапазонов так, чтобы размер диапазаона &amp;lt;tex&amp;gt; d_j &amp;lt;/tex&amp;gt; был равен числу объектов с  префиксом &amp;lt;tex&amp;gt; P + b_j &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; и добавим к префиксу &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; элемент &amp;lt;tex&amp;gt; b_j &amp;lt;/tex&amp;gt; соответствующий диапазону отрезка в котором находится полученное число.&lt;br /&gt;
&lt;br /&gt;
 '''object''' randomObject(n: '''int''', k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер комбинторного объекта, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число различных элемнтов.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = number(prefix) &amp;lt;font color = green&amp;gt; // число комбинаторных объектов с текущим префиксом. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
     '''for''' j = 1 '''to''' k  &lt;br /&gt;
       '''if''' number(prefix + B[j]) &amp;lt; r &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt; {{---}} множество всех возможных элементов. &amp;lt;/font&amp;gt;&lt;br /&gt;
         r = r - number(prefix + B[j]) &amp;lt;font color = green&amp;gt; // если &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; не попало в текщий диапазон {{---}} перейдем к следующему.&amp;lt;/font&amp;gt;&lt;br /&gt;
       '''else''' &lt;br /&gt;
         prefix[i] = b[j]&lt;br /&gt;
         break&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt;O(nk) &amp;lt;/tex&amp;gt;. Количества комбинаторных объектов с заданными префиксами считаются известными, и их подсчет в сложности не учитывается. Стоит отметить, что подсчет количества комбинаторных объектов с заданным префиксом зачастую является задачей с достаточно большой вычислительной сложностью.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности ==&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=Вероятность получить в процессе работы алгоритма некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C(n) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов данного типа длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt; S(P) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных обьектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с таким префиксом.&lt;br /&gt;
|proof=Докажем по [[Математическая индукция|индукции]]:&lt;br /&gt;
&lt;br /&gt;
'''База:''' Заметим, что любой комбинаторный объект имеет пустой префикс (&amp;lt;tex&amp;gt; \varnothing &amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Вероятность получить некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
\dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
'''Переход:''' Пусть вероятность получить префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;. Вероятность получить из &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; некоторый префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить &lt;br /&gt;
префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; \dfrac{S(P')}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Результатом работы данного алгоритма является случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, причем вероятность получения одинакова для каждого результата.&lt;br /&gt;
|proof=Заметим, что результатом работы данного алгоритма является любой из возможных префиксов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;. Любой такой префикс является комбинаторным объектом размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; и наоборот, следовательно число объектов с таким префиксом равно &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;. Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; \dfrac{1}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Примеры решения задач ==&lt;br /&gt;
Рассмотрим примеры использования данного алгоритма для генерации различных типов комбинаторных объектов.&lt;br /&gt;
&lt;br /&gt;
=== Битовые вектора ===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''[[Комбинаторные объекты#Битовые вектора|Битовые вектора]]''' (англ. ''Bit vectors'') {{---}} последовательность нулей и единиц заданной длины.&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим алгоритм получения случайного битового вектора. В битовом векторе может находиться только два типа элементов: &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. Заметим что для любого префикса длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число возможных комбинаторных объектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; одинаково и равно &amp;lt;tex&amp;gt; 2^{n-l} &amp;lt;/tex&amp;gt;, следовательно на каждом шаге алгоритма небходмо выбирать с равной вероятностью &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' randomBitVector(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер битового вектора.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     r = random(0, 1)&lt;br /&gt;
     v[i] = r&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, так как в случае двоичных векторов &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; постоянно и равно &amp;lt;tex&amp;gt; 2 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Правильные скобочные последовательности ===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition ='''[[Правильные скобочные последовательности|Правильная скобочная последовательность]]''' (анлг. ''Correct Bracket Sequence'') {{---}} частный случай скобочной последовательности, определяющийся следующими образами:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;\varepsilon&amp;lt;/tex&amp;gt; (пустая строка) есть правильная скобочная последовательность;&lt;br /&gt;
*пусть &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; {{---}} правильная скобочная последовательность, тогда &amp;lt;tex&amp;gt;(S)&amp;lt;/tex&amp;gt; есть правильная скобочная последовательность;&lt;br /&gt;
*пусть &amp;lt;tex&amp;gt;S1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;S2&amp;lt;/tex&amp;gt; {{---}} правильные скобочные последовательности, тогда &amp;lt;tex&amp;gt;S1S2&amp;lt;/tex&amp;gt; есть правильная скобочная последовательность;&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим алгоритм получения случайной правильной скобочной последовательности. Правильная скобочная последовательность состоит  из двух типов элементов: открывающей и закрывающей скобок, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. &lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''Полуправильная скобочная последовательность''' (анлг. ''Semi-Correct Bracket Sequence'') {{---}} скобочная последовательность такая, что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты.&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим полуправильные скобочные последовательности. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; {{---}} длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; {{---}} баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является полуправильной скобочной последовательностью, и что для любого префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число различных правильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; равно числу полуправильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; с таким же балансом как у &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Научимся считать &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; {{---}} число последовательностей длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; и баланса &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt; l = 0 &amp;lt;/tex&amp;gt;, то ответ понятен сразу: &amp;lt;tex&amp;gt; D[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; D[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; l &amp;gt; 0 &amp;lt;/tex&amp;gt;, тогда переберём, чему мог быть равен последний символ этой последовательности. Если он был равен &amp;lt;tex&amp;gt; '(' &amp;lt;/tex&amp;gt;, то до этого символа мы находились в состоянии &amp;lt;tex&amp;gt; (l-1,b-1) &amp;lt;/tex&amp;gt;. Если он был равен &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt;, то предыдущим было состояние &amp;lt;tex&amp;gt;(l-1,b+1)&amp;lt;/tex&amp;gt;. Таким образом, получаем формулу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;D[l][b] = D[l-1][b-1] + D[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; равны нулю). Этот преподсчет можно выполнить за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем строить префикс следующим образом: на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = D[n-l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; D[n-l-1][b+1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D[n-l-1][b-1] &amp;lt;/tex&amp;gt; , и к префиксу будет прибавляться &amp;lt;tex&amp;gt;'('&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt; если случайное число попало в первый или второй диапазон соответственно.&lt;br /&gt;
&lt;br /&gt;
 '''string''' randomBracketSequence(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} длина скобочной последовательности. &amp;lt;/font&amp;gt;&lt;br /&gt;
   b = 0&lt;br /&gt;
   l = 0&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = D[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' D[n - l - 1][b + 1] &amp;gt;= r&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b + 1&lt;br /&gt;
        result = result + '('&lt;br /&gt;
      '''else'''&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b - 1&lt;br /&gt;
        result = result + ')'&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; при условии что &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; известно для любых &amp;lt;tex&amp;gt; l, b \mid l &amp;lt;= n, b &amp;lt;= n &amp;lt;/tex&amp;gt;. Преподсчет &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; можно выполнить динамически за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Разбиения на множества ===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=[[Комбинаторные объекты#Разбиение на подмножества|'''Разбиение множества''' &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; '''на подмножества''']] (англ. ''Partition of a set'') {{---}} семейство непустых множеств &amp;lt;tex&amp;gt;\{U_{\alpha}\},{\alpha \in A}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; {{---}} некоторое множество индексов, если:&lt;br /&gt;
# &amp;lt;tex&amp;gt;U_{\alpha} \cap U_{\beta} = \emptyset&amp;lt;/tex&amp;gt; для любых &amp;lt;tex&amp;gt;\alpha, \beta \in A&amp;lt;/tex&amp;gt;, таких что &amp;lt;tex&amp;gt;\alpha \not= \beta&amp;lt;/tex&amp;gt;;&lt;br /&gt;
# &amp;lt;tex&amp;gt;X = \bigcup\limits_{\alpha \in A} U_{\alpha}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
==== Разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств ====&lt;br /&gt;
Рассмотрим множество первых &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; натуральных чисел: &amp;lt;tex&amp;gt; N_n = \{1, 2, \ldots, n\} &amp;lt;/tex&amp;gt;. Необходимо разбить его на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; непустых подмножеств &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j \mid 1 \leqslant i &amp;lt; j \leqslant k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_j &amp;lt;/tex&amp;gt;). Для этого будем по очереди добавлять каждое число от &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; в одно из подмножеств и для каждого из подмножеств начиная с &amp;lt;tex&amp;gt; B_n &amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt; B_1 &amp;lt;/tex&amp;gt; будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным). &lt;br /&gt;
&lt;br /&gt;
На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; {{---}} число добавленных элементов и &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; {{---}} число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заданным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества так, чтобы они оказались лексикографически упорядочены, то есть равно числу разбиений &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; непустых подмножеств, что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt; ([[Числа Стирлинга второго рода|числу Стирлинга второго рода]]). Таким образом из префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; мы можем получить следующий префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; двумя способами: &lt;br /&gt;
*Добавить текущий элемент (&amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt;) в одно из &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; незаконченных подмножеств. В таком случае число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
*Сделать текущий элемент последним в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . В таком случае это подмножество станет законченым, следовательно число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Таким образом на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt; &lt;br /&gt;
и &amp;lt;tex&amp;gt; (k-m)\cdot\genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt;. Если случайно сгенерированное число попадет в первый диапазон, то сделаем &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; последним элементом в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . Иначе добавим &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; в случайно выбранное из незаконченных подмножеств (&amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_{k-m}\} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
 '''int[]''' randomSetPartition(n: '''int''' k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''downto''' i = n '''to''' 1                               &lt;br /&gt;
     s = stirling(n - l, k - m) &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; stirling(a, b) &amp;lt;/tex&amp;gt; {{---}} функция возвращающая число Стирлинга второго рода для заданных аргументов. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' stirling(n - l - 1, k - m - 1) &amp;gt;= r&lt;br /&gt;
        result[i] = k - m &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; result[i] &amp;lt;/tex&amp;gt; {{---}} номер подмножества в котором находится элемент &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;. &amp;lt;/font&amp;gt;&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        m = m + 1&lt;br /&gt;
      '''else'''&lt;br /&gt;
        p = random(1, k - m) &amp;lt;font color = green&amp;gt; // Случайным образом выбираем номер одного из незаконченных подмножеств. &amp;lt;/font&amp;gt;&lt;br /&gt;
        result[i] = p&lt;br /&gt;
        l = l + 1&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Так как на каждом шаге интервал случайных чисел разделяется только на на два диапазона, а всего шагов {{---}} &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; то итоговая сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; . Сложность преподсчета чисел Стирлинга второго рода {{---}} &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; если преподсчитать их [[Динамическое программирование | динамически]].&lt;br /&gt;
&lt;br /&gt;
==== Разбиение на случайное число подмножеств ====&lt;br /&gt;
Описаный алгоритм можно применить для получения разбиения множества на случайное число подмножеств. Для этого достаточно случайным образом выбрать число подмножеств из интевала &amp;lt;tex&amp;gt; [1, n] &amp;lt;/tex&amp;gt; , так чтобы вероятность получить число &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; была пропорциональна числу способов разбить &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств (что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{k} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Разделим интервал случайных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;180&amp;quot;&amp;gt; \sum\limits_{i=1}^{n}{\genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i}}&amp;lt;/tex&amp;gt;) на &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; диапазонов, так чтобы размер диапазона &amp;lt;tex&amp;gt; d_i &amp;lt;/tex&amp;gt; был равен&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i} &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. Возьмем &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt; r \in d_k &amp;lt;/tex&amp;gt; и построим случайное разбиение множества из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Метод генерации случайной перестановки, алгоритм Фишера-Йетса|Метод генерации случайной перестановки]]&lt;br /&gt;
*[[Методы генерации случайного сочетания|Методы генерации случайного сочетания]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*Комбинаторные алгоритмы: учебное пособие / Т. И. Федоряева. {{---}} Новосибирск: Новосибирский гос. ун-т, 2011. 118 с. {{---}} ISBN 978-5-4437-0019-9&lt;br /&gt;
*Non-Uniform Random Variate Generation / Luc Devroye. {{---}} Springer, New York, NY, 1986. 843 c. {{---}} ISBN 978-1-4613-8645-2&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Комбинаторика]]&lt;/div&gt;</summary>
		<author><name>217.66.156.56</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67936</id>
		<title>Методы получения случайных комбинаторных объектов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67936"/>
				<updated>2018-12-16T11:38:23Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.156.56: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition = '''[[Комбинаторные объекты]]''' (англ. ''combinatorial objects'') {{---}} конечные множества, на элементы которых могут накладываться определённые ограничения, такие как: различимость или неразличимость элементов, возможность повторения одинаковых элементов и т. п.}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 \ldots, b_k\} &amp;lt;/tex&amp;gt; {{---}} множество различных элементов, которые могут находиться в данном комбинаторном объекте.&lt;br /&gt;
&lt;br /&gt;
Будем получать элементы по порядку: сначала определим, какой элемент будет стоять на первом месте, потом на втором и так далее. Считаем, что мы построили префикс длинны &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; : &amp;lt;tex&amp;gt; P = \{a_1, a_2, \ldots, a_i\} &amp;lt;/tex&amp;gt;. Будем выбирать элемент &amp;lt;tex&amp;gt; a_{i+1} &amp;lt;/tex&amp;gt; из множества всех возможных так, чтобы вероятность выбора элемнта &amp;lt;tex&amp;gt; b \in B &amp;lt;/tex&amp;gt;, была пропорциональна числу комбинторных обьектов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с префиксом &amp;lt;tex&amp;gt; P + b &amp;lt;/tex&amp;gt;. Для этого разобъем отрезок натуральных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. где &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов с текущим префиксом, на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; диапазонов так, чтобы размер диапазаона &amp;lt;tex&amp;gt; d_j &amp;lt;/tex&amp;gt; был равен числу объектов с  префиксом &amp;lt;tex&amp;gt; P + b_j &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; и добавим к префиксу &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; элемент &amp;lt;tex&amp;gt; b_j &amp;lt;/tex&amp;gt; соответствующий диапазону отрезка в котором находится полученное число.&lt;br /&gt;
&lt;br /&gt;
 '''object''' randomObject(n: '''int''', k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер комбинторного объекта, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число различных элемнтов.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = number(prefix) &amp;lt;font color = green&amp;gt; // число комбинаторных объектов с текущим префиксом. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
     '''for''' j = 1 '''to''' k  &lt;br /&gt;
       '''if''' number(prefix + B[j]) &amp;lt; r &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt; {{---}} множество всех возможных элементов. &amp;lt;/font&amp;gt;&lt;br /&gt;
         r = r - number(prefix + B[j]) &amp;lt;font color = green&amp;gt; // если &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; не попало в текщий диапазон {{---}} перейдем к следующему.&amp;lt;/font&amp;gt;&lt;br /&gt;
       '''else''' &lt;br /&gt;
         prefix[i] = b[j]&lt;br /&gt;
         break&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt;O(nk) &amp;lt;/tex&amp;gt;. Количества комбинаторных объектов с заданными префиксами считаются известными, и их подсчет в сложности не учитывается. Стоит отметить, что подсчет количества комбинаторных объектов с заданным префиксом зачастую является задачей с достаточно большой вычислительной сложностью.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности ==&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=Вероятность получить в процессе работы алгоритма некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C(n) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов данного типа длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt; S(P) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных обьектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с таким префиксом.&lt;br /&gt;
|proof=Докажем по [[Математическая индукция|индукции]]:&lt;br /&gt;
&lt;br /&gt;
'''База:''' Заметим, что любой комбинаторный объект имеет пустой префикс (&amp;lt;tex&amp;gt; \varnothing &amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Вероятность получить некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
\dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
'''Переход:''' Пусть вероятность получить префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;. Вероятность получить из &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; некоторый префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить &lt;br /&gt;
префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; \dfrac{S(P')}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Результатом работы данного алгоритма является случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, причем вероятность получения одинакова для каждого результата.&lt;br /&gt;
|proof=Заметим, что результатом работы данного алгоритма является любой из возможных префиксов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;. Любой такой префикс является комбинаторным объектом размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; и наоборот, следовательно число объектов с таким префиксом равно &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;. Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; \dfrac{1}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Примеры решения задач ==&lt;br /&gt;
Рассмотрим примеры использования данного алгоритма для генерации различных типов комбинаторных объектов.&lt;br /&gt;
&lt;br /&gt;
=== Битовые вектора ===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''[[Комбинаторные объекты#Битовые вектора|Битовые вектора]]''' (англ. ''Bit vectors'') {{---}} последовательность нулей и единиц заданной длины.&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим алгоритм получения случайного битового вектора. В битовом векторе может находиться только два типа элементов: &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. Заметим что для любого префикса длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число возможных комбинаторных объектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; одинаково и равно &amp;lt;tex&amp;gt; 2^{n-l} &amp;lt;/tex&amp;gt;, следовательно на каждом шаге алгоритма небходмо выбирать с равной вероятностью &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' randomBitVector(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер битового вектора.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     r = random(0, 1)&lt;br /&gt;
     v[i] = r&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, так как в случае двоичных векторов &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; постоянно и равно &amp;lt;tex&amp;gt; 2 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Правильные скобочные последовательности ===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition ='''[[Правильные скобочные последовательности|Правильная скобочная последовательность]]''' (анлг. ''Correct Bracket Sequences'') {{---}} частный случай скобочной последовательности, определяющийся следующими образами:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;\varepsilon&amp;lt;/tex&amp;gt; (пустая строка) есть правильная скобочная последовательность;&lt;br /&gt;
*пусть &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; {{---}} правильная скобочная последовательность, тогда &amp;lt;tex&amp;gt;(S)&amp;lt;/tex&amp;gt; есть правильная скобочная последовательность;&lt;br /&gt;
*пусть &amp;lt;tex&amp;gt;S1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;S2&amp;lt;/tex&amp;gt; {{---}} правильные скобочные последовательности, тогда &amp;lt;tex&amp;gt;S1S2&amp;lt;/tex&amp;gt; есть правильная скобочная последовательность;&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим алгоритм получения случайной правильной скобочной последовательности. Правильная скобочная последовательность состоит  из двух типов элементов: открывающей и закрывающей скобок, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. &lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''Полуправильная скобочная последовательность''' (анлг. ''Semi-Correct Bracket Sequence'') {{---}} скобочная последовательность такая, что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты.&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим полуправильные скобочные последовательности. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; {{---}} длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; {{---}} баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является полуправильной скобочной последовательностью, и что для любого префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число различных правильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; равно числу полуправильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; с таким же балансом как у &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Научимся считать &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; {{---}} число последовательностей длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; и баланса &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt; l = 0 &amp;lt;/tex&amp;gt;, то ответ понятен сразу: &amp;lt;tex&amp;gt; D[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; D[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; l &amp;gt; 0 &amp;lt;/tex&amp;gt;, тогда переберём, чему мог быть равен последний символ этой последовательности. Если он был равен &amp;lt;tex&amp;gt; '(' &amp;lt;/tex&amp;gt;, то до этого символа мы находились в состоянии &amp;lt;tex&amp;gt; (l-1,b-1) &amp;lt;/tex&amp;gt;. Если он был равен &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt;, то предыдущим было состояние &amp;lt;tex&amp;gt;(l-1,b+1)&amp;lt;/tex&amp;gt;. Таким образом, получаем формулу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;D[l][b] = D[l-1][b-1] + D[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; равны нулю). Этот преподсчет можно выполнить за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем строить префикс следующим образом: на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = D[n-l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; D[n-l-1][b+1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D[n-l-1][b-1] &amp;lt;/tex&amp;gt; , и к префиксу будет прибавляться &amp;lt;tex&amp;gt;'('&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt; если случайное число попало в первый или второй диапазон соответственно.&lt;br /&gt;
&lt;br /&gt;
 '''string''' randomBracketSequence(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} длина скобочной последовательности. &amp;lt;/font&amp;gt;&lt;br /&gt;
   b = 0&lt;br /&gt;
   l = 0&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = D[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' D[n - l - 1][b + 1] &amp;gt;= r&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b + 1&lt;br /&gt;
        result = result + '('&lt;br /&gt;
      '''else'''&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b - 1&lt;br /&gt;
        result = result + ')'&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; при условии что &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; известно для любых &amp;lt;tex&amp;gt; l, b \mid l &amp;lt;= n, b &amp;lt;= n &amp;lt;/tex&amp;gt;. Преподсчет &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; можно выполнить динамически за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Разбиения на множества ===&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=[[Комбинаторные объекты#Разбиение на подмножества|'''Разбиение множества''' &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; '''на подмножества''']] (англ. ''Partition of a set'') {{---}} семейство непустых множеств &amp;lt;tex&amp;gt;\{U_{\alpha}\},{\alpha \in A}&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;A&amp;lt;/tex&amp;gt; {{---}} некоторое множество индексов, если:&lt;br /&gt;
# &amp;lt;tex&amp;gt;U_{\alpha} \cap U_{\beta} = \emptyset&amp;lt;/tex&amp;gt; для любых &amp;lt;tex&amp;gt;\alpha, \beta \in A&amp;lt;/tex&amp;gt;, таких что &amp;lt;tex&amp;gt;\alpha \not= \beta&amp;lt;/tex&amp;gt;;&lt;br /&gt;
# &amp;lt;tex&amp;gt;X = \bigcup\limits_{\alpha \in A} U_{\alpha}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
==== Разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств ====&lt;br /&gt;
Рассмотрим множество первых &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; натуральных чисел: &amp;lt;tex&amp;gt; N_n = \{1, 2, \ldots, n\} &amp;lt;/tex&amp;gt;. Необходимо разбить его на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; непустых подмножеств &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j \mid 1 \leqslant i &amp;lt; j \leqslant k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_j &amp;lt;/tex&amp;gt;). Для этого будем по очереди добавлять каждое число от &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; в одно из подмножеств и для каждого из подмножеств начиная с &amp;lt;tex&amp;gt; B_n &amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt; B_1 &amp;lt;/tex&amp;gt; будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным). &lt;br /&gt;
&lt;br /&gt;
На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; {{---}} число добавленных элементов и &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; {{---}} число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заданным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества так, чтобы они оказались лексикографически упорядочены, то есть равно числу разбиений &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; непустых подмножеств, что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt; ([[Числа Стирлинга второго рода|числу Стирлинга второго рода]]). Таким образом из префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; мы можем получить следующий префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; двумя способами: &lt;br /&gt;
*Добавить текущий элемент (&amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt;) в одно из &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; незаконченных подмножеств. В таком случае число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
*Сделать текущий элемент последним в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . В таком случае это подмножество станет законченым, следовательно число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Таким образом на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt; &lt;br /&gt;
и &amp;lt;tex&amp;gt; (k-m)\cdot\genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt;. Если случайно сгенерированное число попадет в первый диапазон, то сделаем &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; последним элементом в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . Иначе добавим &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; в случайно выбранное из незаконченных подмножеств (&amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_{k-m}\} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
 '''int[]''' randomSetPartition(n: '''int''' k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''downto''' i = n '''to''' 1                               &lt;br /&gt;
     s = stirling(n - l, k - m) &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; stirling(a, b) &amp;lt;/tex&amp;gt; {{---}} функция возвращающая число Стирлинга второго рода для заданных аргументов. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' stirling(n - l - 1, k - m - 1) &amp;gt;= r&lt;br /&gt;
        result[i] = k - m &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; result[i] &amp;lt;/tex&amp;gt; {{---}} номер подмножества в котором находится элемент &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;. &amp;lt;/font&amp;gt;&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        m = m + 1&lt;br /&gt;
      '''else'''&lt;br /&gt;
        p = random(1, k - m) &amp;lt;font color = green&amp;gt; // Случайным образом выбираем номер одного из незаконченных подмножеств. &amp;lt;/font&amp;gt;&lt;br /&gt;
        result[i] = p&lt;br /&gt;
        l = l + 1&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Так как на каждом шаге интервал случайных чисел разделяется только на на два диапазона, а всего шагов {{---}} &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; то итоговая сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; . Сложность преподсчета чисел Стирлинга второго рода {{---}} &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; если преподсчитать их [[Динамическое программирование | динамически]].&lt;br /&gt;
&lt;br /&gt;
==== Разбиение на случайное число подмножеств ====&lt;br /&gt;
Описаный алгоритм можно применить для получения разбиения множества на случайное число подмножеств. Для этого достаточно случайным образом выбрать число подмножеств из интевала &amp;lt;tex&amp;gt; [1, n] &amp;lt;/tex&amp;gt; , так чтобы вероятность получить число &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; была пропорциональна числу способов разбить &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств (что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{k} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Разделим интервал случайных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;180&amp;quot;&amp;gt; \sum\limits_{i=1}^{n}{\genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i}}&amp;lt;/tex&amp;gt;) на &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; диапазонов, так чтобы размер диапазона &amp;lt;tex&amp;gt; d_i &amp;lt;/tex&amp;gt; был равен&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i} &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. Возьмем &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt; r \in d_k &amp;lt;/tex&amp;gt; и построим случайное разбиение множества из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Метод генерации случайной перестановки, алгоритм Фишера-Йетса|Метод генерации случайной перестановки]]&lt;br /&gt;
*[[Методы генерации случайного сочетания|Методы генерации случайного сочетания]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*Комбинаторные алгоритмы: учебное пособие / Т. И. Федоряева. {{---}} Новосибирск: Новосибирский гос. ун-т, 2011. 118 с. {{---}} ISBN 978-5-4437-0019-9&lt;br /&gt;
*Non-Uniform Random Variate Generation / Luc Devroye. {{---}} Springer, New York, NY, 1986. 843 c. {{---}} ISBN 978-1-4613-8645-2&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Комбинаторика]]&lt;/div&gt;</summary>
		<author><name>217.66.156.56</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67932</id>
		<title>Методы получения случайных комбинаторных объектов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67932"/>
				<updated>2018-12-16T11:03:05Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.156.56: /* Правильные скобочные последовательности */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный [[Комбинаторные объекты|комбинаторный объект]] размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 \ldots, b_k\} &amp;lt;/tex&amp;gt; {{---}} множество различных элементов, которые могут находиться в данном комбинаторном объекте.&lt;br /&gt;
&lt;br /&gt;
Будем получать элементы по порядку: сначала определим, какой элемент будет стоять на первом месте, потом на втором и так далее. Считаем, что мы построили префикс длинны &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; : &amp;lt;tex&amp;gt; P = \{a_1, a_2, \ldots, a_i\} &amp;lt;/tex&amp;gt;. Будем выбирать элемент &amp;lt;tex&amp;gt; a_{i+1} &amp;lt;/tex&amp;gt; из множества всех возможных так, чтобы вероятность выбора элемнта &amp;lt;tex&amp;gt; b \in B &amp;lt;/tex&amp;gt;, была пропорциональна числу комбинторных обьектов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с префиксом &amp;lt;tex&amp;gt; P + b &amp;lt;/tex&amp;gt;. Для этого разобъем отрезок натуральных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. где &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов с текущим префиксом, на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; диапазонов так, чтобы размер диапазаона &amp;lt;tex&amp;gt; d_j &amp;lt;/tex&amp;gt; был равен числу объектов с  префиксом &amp;lt;tex&amp;gt; P + b_j &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; и добавим к префиксу &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; элемент &amp;lt;tex&amp;gt; b_j &amp;lt;/tex&amp;gt; соответствующий диапазону отрезка в котором находится полученное число.&lt;br /&gt;
&lt;br /&gt;
 '''object''' randomObject(n: '''int''', k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер комбинторного объекта, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число различных элемнтов.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = number(prefix) &amp;lt;font color = green&amp;gt; // число комбинаторных объектов с текущим префиксом. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
     '''for''' j = 1 '''to''' k  &lt;br /&gt;
       '''if''' number(prefix + B[j]) &amp;lt; r &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt; {{---}} множество всех возможных элементов. &amp;lt;/font&amp;gt;&lt;br /&gt;
         r = r - number(prefix + B[j]) &amp;lt;font color = green&amp;gt; // если &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; не попало в текщий диапазон {{---}} перейдем к следующему.&amp;lt;/font&amp;gt;&lt;br /&gt;
       '''else''' &lt;br /&gt;
         prefix[i] = b[j]&lt;br /&gt;
         break&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt;O(nk) &amp;lt;/tex&amp;gt;. Количества комбинаторных объектов с заданными префиксами считаются известными, и их подсчет в сложности не учитывается. Стоит отметить, что подсчет количества комбинаторных объектов с заданным префиксом зачастую является задачей с достаточно большой вычислительной сложностью.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности ==&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=Вероятность получить в процессе работы алгоритма некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C(n) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов данного типа длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt; S(P) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных обьектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с таким префиксом.&lt;br /&gt;
|proof=Докажем по [[Математическая индукция|индукции]]:&lt;br /&gt;
&lt;br /&gt;
'''База:''' Заметим, что любой комбинаторный объект имеет пустой префикс (&amp;lt;tex&amp;gt; \varnothing &amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Вероятность получить некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
\dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
'''Переход:''' Пусть вероятность получить префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;. Вероятность получить из &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; некоторый префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить &lt;br /&gt;
префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; \dfrac{S(P')}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Результатом работы данного алгоритма является случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, причем вероятность получения одинакова для каждого результата.&lt;br /&gt;
|proof=Заметим, что результатом работы данного алгоритма является любой из возможных префиксов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;. Любой такой префикс является комбинаторным объектом размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; и наоборот, следовательно число объектов с таким префиксом равно &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;. Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; \dfrac{1}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Примеры решения задач ==&lt;br /&gt;
Рассмотрим примеры использования данного алгоритма для генерации различных типов комбинаторных объектов.&lt;br /&gt;
&lt;br /&gt;
=== Битовые вектора ===&lt;br /&gt;
Рассмотрим алгоритм получения случайного [[Комбинаторные объекты#Битовые вектора|битового вектора]]. В битовом векторе может находиться только два типа элементов: &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. Заметим что для любого префикса длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число возможных комбинаторных объектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; одинаково и равно &amp;lt;tex&amp;gt; 2^{n-l} &amp;lt;/tex&amp;gt;, следовательно на каждом шаге алгоритма небходмо выбирать с равной вероятностью &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' randomBitVector(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер битового вектора.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     r = random(0, 1)&lt;br /&gt;
     v[i] = r&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, так как в случае двоичных векторов &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; постоянно и равно &amp;lt;tex&amp;gt; 2 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Правильные скобочные последовательности ===&lt;br /&gt;
Рассмотрим алгоритм получения случайной [[Правильные скобочные последовательности|правильной скобочной последовательности]]. Правильная скобочная последовательность состоит  из двух типов элементов: открывающей и закрывающей скобок, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. &lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''Полуправильная скобочная последовательность''' {{---}} скобочная последовательность такая, что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты.&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим полуправильные скобочные последовательности. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является полуправильной скобочной последовательностью, и что для любого префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число различных правильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; равно числу полуправильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; с таким же балансом как у &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Научимся считать &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; {{---}} число последовательностей длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; и баланса &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt; l = 0 &amp;lt;/tex&amp;gt;, то ответ понятен сразу: &amp;lt;tex&amp;gt; D[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; D[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; l &amp;gt; 0 &amp;lt;/tex&amp;gt;, тогда переберём, чему мог быть равен последний символ этой последовательности. Если он был равен &amp;lt;tex&amp;gt; '(' &amp;lt;/tex&amp;gt;, то до этого символа мы находились в состоянии &amp;lt;tex&amp;gt; (l-1,b-1) &amp;lt;/tex&amp;gt;. Если он был равен &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt;, то предыдущим было состояние &amp;lt;tex&amp;gt;(l-1,b+1)&amp;lt;/tex&amp;gt;. Таким образом, получаем формулу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;D[l][b] = D[l-1][b-1] + D[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; равны нулю). Этот преподсчет можно выполнить за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем строить префикс следующим образом: на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = D[n-l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; D[n-l-1][b+1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D[n-l-1][b-1] &amp;lt;/tex&amp;gt; , и к префиксу будет прибавляться &amp;lt;tex&amp;gt;'('&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt; если случайное число попало в первый или второй диапазон соответственно.&lt;br /&gt;
&lt;br /&gt;
 '''string''' randomBracketSequence(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} длина скобочной последовательности. &amp;lt;/font&amp;gt;&lt;br /&gt;
   b = 0&lt;br /&gt;
   l = 0&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = D[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' D[n - l - 1][b + 1] &amp;gt;= r&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b + 1&lt;br /&gt;
        result = result + '('&lt;br /&gt;
      '''else'''&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b - 1&lt;br /&gt;
        result = result + ')'&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; при условии что &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; известно для любых &amp;lt;tex&amp;gt; l, b \mid l &amp;lt;= n, b &amp;lt;= n &amp;lt;/tex&amp;gt;. Преподсчет &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; можно выполнить динамически за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Разбиения на множества ===&lt;br /&gt;
==== Разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств ====&lt;br /&gt;
Рассмотрим множество первых &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; натуральных чисел: &amp;lt;tex&amp;gt; N_n = \{1, 2, \ldots, n\} &amp;lt;/tex&amp;gt;. Необходимо [[Комбинаторные объекты#Разбиение на подмножества|разбить]] его на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; непустых подмножеств &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j \mid 1 \leqslant i &amp;lt; j \leqslant k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_j &amp;lt;/tex&amp;gt;). Для этого будем по очереди добавлять каждое число от &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; в одно из подмножеств и для каждого из подмножеств начиная с &amp;lt;tex&amp;gt; B_n &amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt; B_1 &amp;lt;/tex&amp;gt; будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным). &lt;br /&gt;
&lt;br /&gt;
На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — число добавленных элементов и &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; — число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заданным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества так, чтобы они оказались лексикографически упорядочены, то есть равно числу разбиений &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; непустых подмножеств, что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt; ([[Числа Стирлинга второго рода|числу Стирлинга второго рода]]). Таким образом из префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; мы можем получить следующий префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; двумя способами: &lt;br /&gt;
*Добавить текущий элемент (&amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt;) в одно из &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; незаконченных подмножеств. В таком случае число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
*Сделать текущий элемент последним в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . В таком случае это подмножество станет законченым, следовательно число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Таким образом на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt; &lt;br /&gt;
и &amp;lt;tex&amp;gt; (k-m)\cdot\genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt;. Если случайно сгенерированное число попадет в первый диапазон, то сделаем &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; последним элементом в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . Иначе добавим &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; в случайно выбранное из незаконченных подмножеств (&amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_{k-m}\} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
 '''int[]''' randomSetPartition(n: '''int''' k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''downto''' i = n '''to''' 1                               &lt;br /&gt;
     s = stirling(n - l, k - m) &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; stirling(a, b) &amp;lt;/tex&amp;gt; {{---}} функция возвращающая число Стирлинга второго рода для заданных аргументов. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' stirling(n - l - 1, k - m - 1) &amp;gt;= r&lt;br /&gt;
        result[i] = k - m &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; result[i] &amp;lt;/tex&amp;gt; {{---}} номер подмножества в котором находится элемент &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;. &amp;lt;/font&amp;gt;&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        m = m + 1&lt;br /&gt;
      '''else'''&lt;br /&gt;
        p = random(1, k - m) &amp;lt;font color = green&amp;gt; // Случайным образом выбираем номер одного из незаконченных подмножеств. &amp;lt;/font&amp;gt;&lt;br /&gt;
        result[i] = p&lt;br /&gt;
        l = l + 1&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Так как на каждом шаге интервал случайных чисел разделяется только на на два диапазона, а всего шагов {{---}} &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; то итоговая сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; . Сложность преподсчета чисел Стирлинга второго рода {{---}} &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; если преподсчитать их [[Динамическое программирование | динамически]].&lt;br /&gt;
&lt;br /&gt;
==== Разбиение на случайное число подмножеств ====&lt;br /&gt;
Описаный алгоритм можно применить для получения разбиения множества на случайное число подмножеств. Для этого достаточно случайным образом выбрать число подмножеств из интевала &amp;lt;tex&amp;gt; [1, n] &amp;lt;/tex&amp;gt; , так чтобы вероятность получить число &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; была пропорциональна числу способов разбить &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств (что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{k} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Разделим интервал случайных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;180&amp;quot;&amp;gt; \sum\limits_{i=1}^{n}{\genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i}}&amp;lt;/tex&amp;gt;) на &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; диапазонов, так чтобы размер диапазона &amp;lt;tex&amp;gt; d_i &amp;lt;/tex&amp;gt; был равен&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i} &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. Возьмем &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt; r \in d_k &amp;lt;/tex&amp;gt; и построим случайное разбиение множества из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Метод генерации случайной перестановки, алгоритм Фишера-Йетса|Метод генерации случайной перестановки]]&lt;br /&gt;
*[[Методы генерации случайного сочетания|Методы генерации случайного сочетания]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*Комбинаторные алгоритмы: учебное пособие / Т. И. Федоряева. {{---}} Новосибирск: Новосибирский гос. ун-т, 2011. 118 с. {{---}} ISBN 978-5-4437-0019-9&lt;br /&gt;
*Non-Uniform Random Variate Generation / Luc Devroye. {{---}} Springer, New York, NY, 1986. 843 c. {{---}} ISBN 978-1-4613-8645-2&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Комбинаторика]]&lt;/div&gt;</summary>
		<author><name>217.66.156.56</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67931</id>
		<title>Методы получения случайных комбинаторных объектов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B9%D0%BD%D1%8B%D1%85_%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B0%D1%82%D0%BE%D1%80%D0%BD%D1%8B%D1%85_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BE%D0%B2&amp;diff=67931"/>
				<updated>2018-12-16T11:02:26Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.156.56: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный [[Комбинаторные объекты|комбинаторный объект]] размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 \ldots, b_k\} &amp;lt;/tex&amp;gt; {{---}} множество различных элементов, которые могут находиться в данном комбинаторном объекте.&lt;br /&gt;
&lt;br /&gt;
Будем получать элементы по порядку: сначала определим, какой элемент будет стоять на первом месте, потом на втором и так далее. Считаем, что мы построили префикс длинны &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; : &amp;lt;tex&amp;gt; P = \{a_1, a_2, \ldots, a_i\} &amp;lt;/tex&amp;gt;. Будем выбирать элемент &amp;lt;tex&amp;gt; a_{i+1} &amp;lt;/tex&amp;gt; из множества всех возможных так, чтобы вероятность выбора элемнта &amp;lt;tex&amp;gt; b \in B &amp;lt;/tex&amp;gt;, была пропорциональна числу комбинторных обьектов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с префиксом &amp;lt;tex&amp;gt; P + b &amp;lt;/tex&amp;gt;. Для этого разобъем отрезок натуральных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. где &amp;lt;tex&amp;gt; s &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов с текущим префиксом, на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; диапазонов так, чтобы размер диапазаона &amp;lt;tex&amp;gt; d_j &amp;lt;/tex&amp;gt; был равен числу объектов с  префиксом &amp;lt;tex&amp;gt; P + b_j &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; и добавим к префиксу &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; элемент &amp;lt;tex&amp;gt; b_j &amp;lt;/tex&amp;gt; соответствующий диапазону отрезка в котором находится полученное число.&lt;br /&gt;
&lt;br /&gt;
 '''object''' randomObject(n: '''int''', k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер комбинторного объекта, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число различных элемнтов.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = number(prefix) &amp;lt;font color = green&amp;gt; // число комбинаторных объектов с текущим префиксом. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
     '''for''' j = 1 '''to''' k  &lt;br /&gt;
       '''if''' number(prefix + B[j]) &amp;lt; r &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; B &amp;lt;/tex&amp;gt; {{---}} множество всех возможных элементов. &amp;lt;/font&amp;gt;&lt;br /&gt;
         r = r - number(prefix + B[j]) &amp;lt;font color = green&amp;gt; // если &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; не попало в текщий диапазон {{---}} перейдем к следующему.&amp;lt;/font&amp;gt;&lt;br /&gt;
       '''else''' &lt;br /&gt;
         prefix[i] = b[j]&lt;br /&gt;
         break&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt;O(nk) &amp;lt;/tex&amp;gt;. Количества комбинаторных объектов с заданными префиксами считаются известными, и их подсчет в сложности не учитывается. Стоит отметить, что подсчет количества комбинаторных объектов с заданным префиксом зачастую является задачей с достаточно большой вычислительной сложностью.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности ==&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=Вероятность получить в процессе работы алгоритма некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; C(n) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных объектов данного типа длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, а &amp;lt;tex&amp;gt; S(P) &amp;lt;/tex&amp;gt; {{---}} число различных комбинаторных обьектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с таким префиксом.&lt;br /&gt;
|proof=Докажем по [[Математическая индукция|индукции]]:&lt;br /&gt;
&lt;br /&gt;
'''База:''' Заметим, что любой комбинаторный объект имеет пустой префикс (&amp;lt;tex&amp;gt; \varnothing &amp;lt;/tex&amp;gt;), следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Вероятность получить некоторый префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
\dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
&lt;br /&gt;
'''Переход:''' Пусть вероятность получить префикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;. Вероятность получить из &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; некоторый префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить &lt;br /&gt;
префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; \dfrac{S(P)}{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \dfrac{S(P')}{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; \dfrac{S(P')}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Результатом работы данного алгоритма является случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;, причем вероятность получения одинакова для каждого результата.&lt;br /&gt;
|proof=Заметим, что результатом работы данного алгоритма является любой из возможных префиксов размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt;. Любой такой префикс является комбинаторным объектом размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; и наоборот, следовательно число объектов с таким префиксом равно &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;. Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; \dfrac{1}{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Примеры решения задач ==&lt;br /&gt;
Рассмотрим примеры использования данного алгоритма для генерации различных типов комбинаторных объектов.&lt;br /&gt;
&lt;br /&gt;
=== Битовые вектора ===&lt;br /&gt;
Рассмотрим алгоритм получения случайного [[Комбинаторные объекты#Битовые вектора|битового вектора]]. В битовом векторе может находиться только два типа элементов: &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. Заметим что для любого префикса длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число возможных комбинаторных объектов длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; одинаково и равно &amp;lt;tex&amp;gt; 2^{n-l} &amp;lt;/tex&amp;gt;, следовательно на каждом шаге алгоритма небходмо выбирать с равной вероятностью &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' randomBitVector(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} размер битового вектора.&amp;lt;/font&amp;gt;&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     r = random(0, 1)&lt;br /&gt;
     v[i] = r&lt;br /&gt;
   '''return''' prefix&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, так как в случае двоичных векторов &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; постоянно и равно &amp;lt;tex&amp;gt; 2 &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Правильные скобочные последовательности ===&lt;br /&gt;
Рассмотрим алгоритм получения случайной [[Правильные скобочные последовательности|правильной скобочной последовательности]]. Правильная скобочная последовательность состоит  из двух типов элементов: открывающей и закрывающей скобок, следовательно &amp;lt;tex&amp;gt; k = 2 &amp;lt;/tex&amp;gt;. &lt;br /&gt;
{{Определение&lt;br /&gt;
|definition='''Полуправильная скобочная последовательность''' {{---}} скобочная последовательность такая, что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты.&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим полуправильные скобочные последовательности. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является полуправильной скобочной последовательностью, и что для любого префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; число различных правильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; равно числу полуправильных скобочных последовательностей длины &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; с таким же балансом как у &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Научимся считать &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; {{---}} число последовательностей длины &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; и баланса &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt; l = 0 &amp;lt;/tex&amp;gt;, то ответ понятен сразу: &amp;lt;tex&amp;gt; D[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; D[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; l &amp;gt; 0 &amp;lt;/tex&amp;gt;, тогда переберём, чему мог быть равен последний символ этой последовательности. Если он был равен &amp;lt;tex&amp;gt; '(' &amp;lt;/tex&amp;gt;, то до этого символа мы находились в состоянии &amp;lt;tex&amp;gt; (l-1,b-1) &amp;lt;/tex&amp;gt;. Если он был равен &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt;, то предыдущим было состояние &amp;lt;tex&amp;gt;(l-1,b+1)&amp;lt;/tex&amp;gt;. Таким образом, получаем формулу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;D[l][b] = D[l-1][b-1] + D[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; D[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; равны нулю). Этот преподсчет можно выполнить за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Будем строить префикс следующим образом: на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = D[n-l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; D[n-l-1][b+1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; D[n-l-1][b-1] &amp;lt;/tex&amp;gt; , и к префиксу будет прибавляться &amp;lt;tex&amp;gt;'('&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;')'&amp;lt;/tex&amp;gt; если случайное число попало в первый или второй диапазон соответственно.&lt;br /&gt;
&lt;br /&gt;
 '''string''' randomBracketSequence(n: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} длина скобочной последовательности. &amp;lt;/font&amp;gt;&lt;br /&gt;
   b = 0&lt;br /&gt;
   l = 0&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     s = D[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' D[n - l - 1][b + 1] &amp;gt;= r&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b + 1&lt;br /&gt;
        result = result + '('&lt;br /&gt;
      '''else'''&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        b = b - 1&lt;br /&gt;
        result = result + ')'&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; при условии что &amp;lt;tex&amp;gt; D[l][b]n &amp;lt;/tex&amp;gt; известно для любых &amp;lt;tex&amp;gt; l, b \mid l &amp;lt;= n, b &amp;lt;= n &amp;lt;/tex&amp;gt;. Преподсчет &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; можно выполнить динамически за &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Разбиения на множества ===&lt;br /&gt;
==== Разбиение на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств ====&lt;br /&gt;
Рассмотрим множество первых &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; натуральных чисел: &amp;lt;tex&amp;gt; N_n = \{1, 2, \ldots, n\} &amp;lt;/tex&amp;gt;. Необходимо [[Комбинаторные объекты#Разбиение на подмножества|разбить]] его на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; непустых подмножеств &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j \mid 1 \leqslant i &amp;lt; j \leqslant k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_j &amp;lt;/tex&amp;gt;). Для этого будем по очереди добавлять каждое число от &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt; 1 &amp;lt;/tex&amp;gt; в одно из подмножеств и для каждого из подмножеств начиная с &amp;lt;tex&amp;gt; B_n &amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt; B_1 &amp;lt;/tex&amp;gt; будем выбирать какой элемент будет добавлен в него последним(т.е. будет минимальным). &lt;br /&gt;
&lt;br /&gt;
На каждом шаге префиксом считаем текущее разбиение. Оно характеризуется двумя значениями: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — число добавленных элементов и &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; — число подмножеств для которых определен последний элемент. Заметим, что количество разбиений на подмножества с заданным префиксом равно числу способов разбить еще не добавленные элементы на еще не законченные подмножества так, чтобы они оказались лексикографически упорядочены, то есть равно числу разбиений &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; непустых подмножеств, что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt; ([[Числа Стирлинга второго рода|числу Стирлинга второго рода]]). Таким образом из префикса &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; мы можем получить следующий префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; двумя способами: &lt;br /&gt;
*Добавить текущий элемент (&amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt;) в одно из &amp;lt;tex&amp;gt; k-m &amp;lt;/tex&amp;gt; незаконченных подмножеств. В таком случае число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt; .&lt;br /&gt;
*Сделать текущий элемент последним в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . В таком случае это подмножество станет законченым, следовательно число обьектов с префиксом &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; будет равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
Таким образом на каждом шаге интервал случайных чисел &amp;lt;tex&amp;gt; [0, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l}{k-m} &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m-1} &amp;lt;/tex&amp;gt; &lt;br /&gt;
и &amp;lt;tex&amp;gt; (k-m)\cdot\genfrac{\lbrace}{\rbrace}{0pt}{0}{n-l-1}{k-m} &amp;lt;/tex&amp;gt;. Если случайно сгенерированное число попадет в первый диапазон, то сделаем &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; последним элементом в подмножестве &amp;lt;tex&amp;gt; B_{k-m} &amp;lt;/tex&amp;gt; . Иначе добавим &amp;lt;tex&amp;gt; n-l &amp;lt;/tex&amp;gt; в случайно выбранное из незаконченных подмножеств (&amp;lt;tex&amp;gt; \{B_1, B_2, \ldots, B_{k-m}\} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
 '''int[]''' randomSetPartition(n: '''int''' k: '''int'''): &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''downto''' i = n '''to''' 1                               &lt;br /&gt;
     s = stirling(n - l, k - m) &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; stirling(a, b) &amp;lt;/tex&amp;gt; {{---}} функция возвращающая число Стирлинга второго рода для заданных аргументов. &amp;lt;/font&amp;gt;&lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' stirling(n - l - 1, k - m - 1) &amp;gt;= r&lt;br /&gt;
        result[i] = k - m &amp;lt;font color = green&amp;gt; // &amp;lt;tex&amp;gt; result[i] &amp;lt;/tex&amp;gt; {{---}} номер подмножества в котором находится элемент &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;. &amp;lt;/font&amp;gt;&lt;br /&gt;
        l = l + 1&lt;br /&gt;
        m = m + 1&lt;br /&gt;
      '''else'''&lt;br /&gt;
        p = random(1, k - m) &amp;lt;font color = green&amp;gt; // Случайным образом выбираем номер одного из незаконченных подмножеств. &amp;lt;/font&amp;gt;&lt;br /&gt;
        result[i] = p&lt;br /&gt;
        l = l + 1&lt;br /&gt;
   '''return''' result&lt;br /&gt;
&lt;br /&gt;
Так как на каждом шаге интервал случайных чисел разделяется только на на два диапазона, а всего шагов {{---}} &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; то итоговая сложность алгоритма {{---}} &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt; . Сложность преподсчета чисел Стирлинга второго рода {{---}} &amp;lt;tex&amp;gt; O(n^2) &amp;lt;/tex&amp;gt; если преподсчитать их [[Динамическое программирование | динамически]].&lt;br /&gt;
&lt;br /&gt;
==== Разбиение на случайное число подмножеств ====&lt;br /&gt;
Описаный алгоритм можно применить для получения разбиения множества на случайное число подмножеств. Для этого достаточно случайным образом выбрать число подмножеств из интевала &amp;lt;tex&amp;gt; [1, n] &amp;lt;/tex&amp;gt; , так чтобы вероятность получить число &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; была пропорциональна числу способов разбить &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств (что равно &amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{k} &amp;lt;/tex&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Разделим интервал случайных чисел &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; s = &amp;lt;/tex&amp;gt; &amp;lt;tex dpi=&amp;quot;180&amp;quot;&amp;gt; \sum\limits_{i=1}^{n}{\genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i}}&amp;lt;/tex&amp;gt;) на &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; диапазонов, так чтобы размер диапазона &amp;lt;tex&amp;gt; d_i &amp;lt;/tex&amp;gt; был равен&amp;lt;tex&amp;gt; \genfrac{\lbrace}{\rbrace}{0pt}{0}{n}{i} &amp;lt;/tex&amp;gt;. С помощью функции для генерации случайного числа получим число &amp;lt;tex&amp;gt; r &amp;lt;/tex&amp;gt; в интервале &amp;lt;tex&amp;gt; [1, s] &amp;lt;/tex&amp;gt;. Возьмем &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt; r \in d_k &amp;lt;/tex&amp;gt; и построим случайное разбиение множества из &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; элементов на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; подмножеств.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Метод генерации случайной перестановки, алгоритм Фишера-Йетса|Метод генерации случайной перестановки]]&lt;br /&gt;
*[[Методы генерации случайного сочетания|Методы генерации случайного сочетания]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*Комбинаторные алгоритмы: учебное пособие / Т. И. Федоряева. {{---}} Новосибирск: Новосибирский гос. ун-т, 2011. 118 с. {{---}} ISBN 978-5-4437-0019-9&lt;br /&gt;
*Non-Uniform Random Variate Generation / Luc Devroye. {{---}} Springer, New York, NY, 1986. 843 c. {{---}} ISBN 978-1-4613-8645-2&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Комбинаторика]]&lt;/div&gt;</summary>
		<author><name>217.66.156.56</name></author>	</entry>

	</feed>