<?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=Cczy</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=Cczy"/>
		<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/Cczy"/>
		<updated>2026-08-03T23:04:01Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%BE%D0%B2&amp;diff=72080</id>
		<title>Обсуждение:Факторизация графов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%BE%D0%B2&amp;diff=72080"/>
				<updated>2019-12-29T18:24:01Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Задача о поиске произвольного f-фактора */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Определение&lt;br /&gt;
|definition = '''&amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-фактор''' — [[Основные определения теории графов|регулярный]] остовный подграф степени &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Если граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; представляет собой сумму &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-факторов, то их объединение называется &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-факторизацией, а сам граф &amp;lt;tex&amp;gt;G&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;
|definition = Пусть задана функция &amp;lt;tex&amp;gt;f : V(G) \rightarrow \mathbb{N}&amp;lt;/tex&amp;gt;, такая что &amp;lt;tex&amp;gt;\forall~v \in V(G):f(v)\leq \text{deg}(v)&amp;lt;/tex&amp;gt;. Тогда остовный подграф &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; в котором степень каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; называется '''&amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактором'''.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:1-A-general-graph-G-with-a-3-regular-factor-2-A-general-graph-G-with-an-f-factor (1).png|700px|thumb|centre| Примеры факторов в графе: (1) {{---}} &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;-фактор, (2) {{---}} &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор (значения &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; указаны возле вершин)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Задача о поиске произвольного &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактора ==&lt;br /&gt;
&lt;br /&gt;
Сведем задачу о поиске &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактора к задаче о поиске наибольшего паросочетания.&lt;br /&gt;
&lt;br /&gt;
Пусть дан граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и функция &amp;lt;tex&amp;gt;f : V(G) \rightarrow \mathbb{N}&amp;lt;/tex&amp;gt;. Построим граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; следующим образом. &lt;br /&gt;
# Для каждого ребра &amp;lt;tex&amp;gt;(u,w)\in E(G)&amp;lt;/tex&amp;gt; добавим в граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; по одной новой вершине в множества &amp;lt;tex&amp;gt;S(u)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S(w)&amp;lt;/tex&amp;gt;, и соединим их ребром &amp;lt;tex&amp;gt;(e(u),e(w))&amp;lt;/tex&amp;gt;. В результате каждой вершине &amp;lt;tex&amp;gt;v \in V(G)&amp;lt;/tex&amp;gt; будет соответствовать множество &amp;lt;tex&amp;gt;S(v) \subset V(G^*)&amp;lt;/tex&amp;gt; такое что &amp;lt;tex&amp;gt;|S(v)|=deg(v)&amp;lt;/tex&amp;gt;; Каждому ребру &amp;lt;tex&amp;gt;(u,w) \in E(G)&amp;lt;/tex&amp;gt; будет соответствовать ребро &amp;lt;tex&amp;gt;(e(u),e(w))&amp;lt;/tex&amp;gt;, причем ни для каких двух ребер из &amp;lt;tex&amp;gt;E(G)&amp;lt;/tex&amp;gt; концы соответствующих им ребер в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; не пересекаются.&lt;br /&gt;
# Для каждой вершины &amp;lt;tex&amp;gt;v\in V(G)&amp;lt;/tex&amp;gt; добавим в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; новые &amp;lt;tex&amp;gt;deg(v)-f(v)&amp;lt;/tex&amp;gt; вершин, образующие множество &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt;. Каждую вершину из &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt; свяжем ребром с каждой вершиной из &amp;lt;tex&amp;gt;S(v)&amp;lt;/tex&amp;gt;. В результате для каждой вершины &amp;lt;tex&amp;gt;v \in V(G)&amp;lt;/tex&amp;gt; Множество &amp;lt;tex&amp;gt;S(v)\cup T(v)&amp;lt;/tex&amp;gt; образует полный двудольный граф. &lt;br /&gt;
&lt;br /&gt;
[[Файл:A-general-graph-G-with-an-f-factor-and-the-corresponding-simple-graph-G-with-a.png|700px|thumb|centre| Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и соответствующий ему граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement = &lt;br /&gt;
Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; имеет &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор тогда и только тогда, когда соответствующий графу &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и функции &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt; граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; имеет совершенное паросочетание.&lt;br /&gt;
|proof = &lt;br /&gt;
&amp;lt;tex&amp;gt;\Rightarrow&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; имеет &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt;. Построим паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; для графа &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; следующим образом:&lt;br /&gt;
# Для каждого ребра &amp;lt;tex&amp;gt;(u,w)\in G_f&amp;lt;/tex&amp;gt; добавим в &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;  соответствующее ему ребро из &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; . Теперь для каждой вершины &amp;lt;tex&amp;gt;v \in V(g)&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; вершин из множества &amp;lt;tex&amp;gt;S(v)&amp;lt;/tex&amp;gt; покрыты &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; .&lt;br /&gt;
# Для каждой вершины &amp;lt;tex&amp;gt;v \in V(g)&amp;lt;/tex&amp;gt; пусть &amp;lt;tex&amp;gt;R(v)\subset S(v)&amp;lt;/tex&amp;gt; {{---}} множество вершин еще не покрытых &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;R(v)\cup T(v)&amp;lt;/tex&amp;gt; является полным двудольным графом, причем размер каждой из долей равен &amp;lt;tex&amp;gt;deg(v)-f(v)&amp;lt;/tex&amp;gt;, следовательно этот граф имеет совершенное паросочетание &amp;lt;tex&amp;gt;M_v&amp;lt;/tex&amp;gt;. Добавим каждое ребро из &amp;lt;tex&amp;gt;M_v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;.&lt;br /&gt;
В результате каждая вершина в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; покрыта &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; является совершенным паросочетанием.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\Leftarrow&amp;lt;/tex&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; имеет совершенное паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;. Для каждой вершины &amp;lt;tex&amp;gt;v\in V(G)&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt; является независимым множеством и полностью покрыто &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, следовательно множество &amp;lt;tex&amp;gt;R(v)\subset S(v)&amp;lt;/tex&amp;gt; покрыто ребрами, концы которых лежат в &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt;, а значит каждая вершина из &amp;lt;tex&amp;gt;S(v)\setminus R(v)&amp;lt;/tex&amp;gt; покрыта ребром, второй конец которого принадлежит &amp;lt;tex&amp;gt;S(w) : w \in V(G)&amp;lt;/tex&amp;gt;, причем &amp;lt;tex&amp;gt;|S(v)\setminus R(v)| = deg(v)-(deg(v)-f(v))=f(v)&amp;lt;/tex&amp;gt;. Поэтому если мы добавим в &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; все ребра соответствующие ребрам из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; покрывающим &amp;lt;tex&amp;gt;S(v)\setminus R(v) : v \in V(G)&amp;lt;/tex&amp;gt;, то есть все ребра из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; концы которых лежат в множествах  &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, то степень каждой вершины &amp;lt;tex&amp;gt;v \in G_f&amp;lt;/tex&amp;gt; будет равна &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; будет являться &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактором.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Из доказательства напрямую следует, что для нахождения &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактора графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; достаточно найти совершенное паросочетание в графе &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt;. Т.к. &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; в общем случае не является двудольным, для решения этой задачи можно воспользваться [https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B6%D0%B0%D1%82%D0%B8%D1%8F_%D1%86%D0%B2%D0%B5%D1%82%D0%BA%D0%BE%D0%B2 Алгоритмом Эдмондса для поиска наибольшего паросочетания].&lt;/div&gt;</summary>
		<author><name>Cczy</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%BE%D0%B2&amp;diff=72079</id>
		<title>Обсуждение:Факторизация графов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%BE%D0%B2&amp;diff=72079"/>
				<updated>2019-12-29T18:00:55Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Определение&lt;br /&gt;
|definition = '''&amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-фактор''' — [[Основные определения теории графов|регулярный]] остовный подграф степени &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Если граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; представляет собой сумму &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-факторов, то их объединение называется &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-факторизацией, а сам граф &amp;lt;tex&amp;gt;G&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;
|definition = Пусть задана функция &amp;lt;tex&amp;gt;f : V(G) \rightarrow \mathbb{N}&amp;lt;/tex&amp;gt;, такая что &amp;lt;tex&amp;gt;\forall~v \in V(G):f(v)\leq \text{deg}(v)&amp;lt;/tex&amp;gt;. Тогда остовный подграф &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; в котором степень каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; называется '''&amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактором'''.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:1-A-general-graph-G-with-a-3-regular-factor-2-A-general-graph-G-with-an-f-factor (1).png|700px|thumb|centre| Примеры факторов в графе: (1) {{---}} &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;-фактор, (2) {{---}} &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор (значения &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; указаны возле вершин)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Задача о поиске произвольного &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактора ==&lt;br /&gt;
&lt;br /&gt;
Сведем задачу о поиске &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактора к задаче о поиске наибольшего паросочетания.&lt;br /&gt;
&lt;br /&gt;
Пусть дан граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и функция &amp;lt;tex&amp;gt;f : V(G) \rightarrow \mathbb{N}&amp;lt;/tex&amp;gt;. Построим граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; следующим образом. &lt;br /&gt;
# Для каждого ребра &amp;lt;tex&amp;gt;(u,w)\in E(G)&amp;lt;/tex&amp;gt; добавим в граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; две новых вершины &amp;lt;tex&amp;gt;e(u)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;e(w)&amp;lt;/tex&amp;gt;, соответствующие &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, и соединим их ребром. В результате каждой вершине &amp;lt;tex&amp;gt;v \in V(G)&amp;lt;/tex&amp;gt; будет соответствовать множество &amp;lt;tex&amp;gt;S(v) \subset V(G^*)&amp;lt;/tex&amp;gt; такое что &amp;lt;tex&amp;gt;|S(v)|=deg(v)&amp;lt;/tex&amp;gt;; Каждому ребру &amp;lt;tex&amp;gt;(u,w) \in E(G)&amp;lt;/tex&amp;gt; соответствует ребро &amp;lt;tex&amp;gt;(e(u),e(w))&amp;lt;/tex&amp;gt;, причем ни для каких двух ребер из &amp;lt;tex&amp;gt;E(G)&amp;lt;/tex&amp;gt; концы соответствующих им ребер в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; не пересекаются.&lt;br /&gt;
# Для каждой вершины &amp;lt;tex&amp;gt;v\in V(G)&amp;lt;/tex&amp;gt; добавим в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; новые &amp;lt;tex&amp;gt;deg(v)-f(v)&amp;lt;/tex&amp;gt; вершин, образующие множество &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt;. Каждую вершину из &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt; свяжем ребром с каждой вершиной из &amp;lt;tex&amp;gt;S(v)&amp;lt;/tex&amp;gt;. В результате для каждой вершины &amp;lt;tex&amp;gt;v \in V(G)&amp;lt;/tex&amp;gt; Множество &amp;lt;tex&amp;gt;S(v)\cup T(v)&amp;lt;/tex&amp;gt; образует полный двудольный граф. &lt;br /&gt;
&lt;br /&gt;
[[Файл:A-general-graph-G-with-an-f-factor-and-the-corresponding-simple-graph-G-with-a.png|700px|thumb|centre| Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и соответствующий ему граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement = &lt;br /&gt;
Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; имеет &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор тогда и только тогда, когда соответствующий графу &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и функции &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt; граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; имеет совершенное паросочетание.&lt;br /&gt;
|proof = &lt;br /&gt;
&amp;lt;tex&amp;gt;\Rightarrow&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; имеет &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt;. Построим паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; для графа &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; следующим образом:&lt;br /&gt;
# Для каждого ребра &amp;lt;tex&amp;gt;(u,w)\in G_f&amp;lt;/tex&amp;gt; добавим в &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;  соответствующее ему ребро из &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; . Теперь для каждой вершины &amp;lt;tex&amp;gt;v \in V(g)&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; вершин из множества &amp;lt;tex&amp;gt;S(v)&amp;lt;/tex&amp;gt; покрыты &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; .&lt;br /&gt;
# Для каждой вершины &amp;lt;tex&amp;gt;v \in V(g)&amp;lt;/tex&amp;gt; пусть &amp;lt;tex&amp;gt;R(v)\subset S(v)&amp;lt;/tex&amp;gt; {{---}} множество вершин еще не покрытых &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;R(v)\cup T(v)&amp;lt;/tex&amp;gt; является полным двудольным графом, причем размер каждой из долей равен &amp;lt;tex&amp;gt;deg(v)-f(v)&amp;lt;/tex&amp;gt;, следовательно этот граф имеет совершенное паросочетание &amp;lt;tex&amp;gt;M_v&amp;lt;/tex&amp;gt;. Добавим каждое ребро из &amp;lt;tex&amp;gt;M_v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;.&lt;br /&gt;
В результате каждая вершина в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; покрыта &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; является совершенным паросочетанием.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\Leftarrow&amp;lt;/tex&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; имеет совершенное паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;. Для каждой вершины &amp;lt;tex&amp;gt;v\in V(G)&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt; является независимым множеством и полностью покрыто &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, следовательно множество &amp;lt;tex&amp;gt;R(v)\subset S(v)&amp;lt;/tex&amp;gt; покрыто ребрами, концы которых лежат в &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt;, а значит каждая вершина из &amp;lt;tex&amp;gt;S(v)\setminus R(v)&amp;lt;/tex&amp;gt; покрыта ребром, второй конец которого принадлежит &amp;lt;tex&amp;gt;S(w) : w \in V(G)&amp;lt;/tex&amp;gt;, причем &amp;lt;tex&amp;gt;|S(v)\setminus R(v)| = deg(v)-(deg(v)-f(v))=f(v)&amp;lt;/tex&amp;gt;. Поэтому если мы добавим в &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; все ребра соответствующие ребрам из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; покрывающим &amp;lt;tex&amp;gt;S(v)\setminus R(v) : v \in V(G)&amp;lt;/tex&amp;gt;, то есть все ребра из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; концы которых лежат в множествах  &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, то степень каждой вершины &amp;lt;tex&amp;gt;v \in G_f&amp;lt;/tex&amp;gt; будет равна &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; будет являться &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактором.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Из доказательства напрямую следует, что для нахождения &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактора графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; достаточно найти совершенное паросочетание в графе &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt;. Т.к. &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; в общем случае не является двудольным, для решения этой задачи можно воспользваться [https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B6%D0%B0%D1%82%D0%B8%D1%8F_%D1%86%D0%B2%D0%B5%D1%82%D0%BA%D0%BE%D0%B2 Алгоритмом Эдмондса для поиска наибольшего паросочетания].&lt;/div&gt;</summary>
		<author><name>Cczy</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%BE%D0%B2&amp;diff=72078</id>
		<title>Обсуждение:Факторизация графов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%BE%D0%B2&amp;diff=72078"/>
				<updated>2019-12-29T17:53:37Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Определение&lt;br /&gt;
|definition = '''&amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-фактор''' — [[Основные определения теории графов|регулярный]] остовный подграф степени &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Если граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; представляет собой сумму &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-факторов, то их объединение называется &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-факторизацией, а сам граф &amp;lt;tex&amp;gt;G&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;
|definition = Пусть задана функция &amp;lt;tex&amp;gt;f : V(G) \rightarrow \mathbb{N}&amp;lt;/tex&amp;gt;, такая что &amp;lt;tex&amp;gt;\forall~v \in V(G):f(v)\leq \text{deg}(v)&amp;lt;/tex&amp;gt;. Тогда остовный подграф &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; в котором степень каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; называется '''&amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактором'''.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:1-A-general-graph-G-with-a-3-regular-factor-2-A-general-graph-G-with-an-f-factor (1).png|700px|thumb|centre| Примеры факторов в графе: (1) {{---}} &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;-фактор, (2) {{---}} &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор (значения &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; указаны возле вершин)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Задача о поиске произвольного &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактора ==&lt;br /&gt;
&lt;br /&gt;
Пусть дан граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и функция &amp;lt;tex&amp;gt;f : V(G) \rightarrow \mathbb{N}&amp;lt;/tex&amp;gt;. Построим граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; следующим образом. &lt;br /&gt;
# Для каждого ребра &amp;lt;tex&amp;gt;(u,w)\in E(G)&amp;lt;/tex&amp;gt; добавим в граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; две новых вершины &amp;lt;tex&amp;gt;e(u)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;e(w)&amp;lt;/tex&amp;gt;, соответствующие &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, и соединим их ребром. В результате каждой вершине &amp;lt;tex&amp;gt;v \in V(G)&amp;lt;/tex&amp;gt; будет соответствовать множество &amp;lt;tex&amp;gt;S(v) \subset V(G_f^*)&amp;lt;/tex&amp;gt; такое что &amp;lt;tex&amp;gt;|S(v)|=deg(v)&amp;lt;/tex&amp;gt;; Каждому ребру &amp;lt;tex&amp;gt;(u,w) \in E(G)&amp;lt;/tex&amp;gt; соответствует ребро &amp;lt;tex&amp;gt;(e(u),e(w))&amp;lt;/tex&amp;gt;, причем ни для каких двух ребер из &amp;lt;tex&amp;gt;E(G)&amp;lt;/tex&amp;gt; концы соответствующих им ребер в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; не пересекаются.&lt;br /&gt;
# Для каждой вершины &amp;lt;tex&amp;gt;v\in V(G)&amp;lt;/tex&amp;gt; добавим в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; новые &amp;lt;tex&amp;gt;deg(v)-f(v)&amp;lt;/tex&amp;gt; вершин, образующие множество &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt;. Каждую вершину из &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt; свяжем ребром с каждой вершиной из &amp;lt;tex&amp;gt;S(v)&amp;lt;/tex&amp;gt;. В результате для каждой вершины &amp;lt;tex&amp;gt;v \in V(G)&amp;lt;/tex&amp;gt; Множество &amp;lt;tex&amp;gt;S(v)\cup T(v)&amp;lt;/tex&amp;gt; образует полный двудольный граф. &lt;br /&gt;
&lt;br /&gt;
[[Файл:A-general-graph-G-with-an-f-factor-and-the-corresponding-simple-graph-G-with-a.png|700px|thumb|centre| Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и соответствующий ему граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement = &lt;br /&gt;
Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; имеет &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор тогда и только тогда, когда соответствующий графу &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и функции &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt; граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; имеет совершенное паросочетание.&lt;br /&gt;
|proof = &lt;br /&gt;
&amp;lt;tex&amp;gt;\Rightarrow&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; имеет &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt;. Построим паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; для графа &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; следующим образом:&lt;br /&gt;
# Для каждого ребра &amp;lt;tex&amp;gt;(u,w)\in G_f&amp;lt;/tex&amp;gt; добавим в &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;  соответствующее ему ребро из &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; . Теперь для каждой вершины &amp;lt;tex&amp;gt;v \in V(g)&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; вершин из множества &amp;lt;tex&amp;gt;S(v)&amp;lt;/tex&amp;gt; покрыты &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; .&lt;br /&gt;
# Для каждой вершины &amp;lt;tex&amp;gt;v \in V(g)&amp;lt;/tex&amp;gt; пусть &amp;lt;tex&amp;gt;R(v)\subset S(v)&amp;lt;/tex&amp;gt; {{---}} множество вершин еще не покрытых &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;R(v)\cup T(v)&amp;lt;/tex&amp;gt; является полным двудольным графом, причем размер каждой из долей равен &amp;lt;tex&amp;gt;deg(v)-f(v)&amp;lt;/tex&amp;gt;, следовательно этот граф имеет совершенное паросочетание &amp;lt;tex&amp;gt;M_v&amp;lt;/tex&amp;gt;. Добавим каждое ребро из &amp;lt;tex&amp;gt;M_v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;.&lt;br /&gt;
В результате каждая вершина в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; покрыта &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; является совершенным паросочетанием.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\Leftarrow&amp;lt;/tex&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; имеет совершенное паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;. Для каждой вершины &amp;lt;tex&amp;gt;v\in V(G)&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt; является независимым множеством и полностью покрыто &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, следовательно множество &amp;lt;tex&amp;gt;R(v)\subset S(v)&amp;lt;/tex&amp;gt; покрыто ребрами, концы которых лежат в &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt;, а значит каждая вершина из &amp;lt;tex&amp;gt;S(v)\setminus R(v)&amp;lt;/tex&amp;gt; покрыта ребром, второй конец которого принадлежит &amp;lt;tex&amp;gt;S(w) : w \in V(G)&amp;lt;/tex&amp;gt;, причем &amp;lt;tex&amp;gt;|S(v)\setminus R(v)| = deg(v)-(deg(v)-f(v))=f(v)&amp;lt;/tex&amp;gt;. Поэтому если мы добавим в &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; все ребра соответствующие ребрам из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; покрывающим &amp;lt;tex&amp;gt;S(v)\setminus R(v) : v \in V(G)&amp;lt;/tex&amp;gt;, то есть все ребра из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; концы которых лежат в множествах  &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, то степень каждой вершины &amp;lt;tex&amp;gt;v \in G_f&amp;lt;/tex&amp;gt; будет равна &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; будет являться &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактором.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Из доказательства напрямую следует, что для нахождения &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактора графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; достаточно найти совершенное паросочетание в графе &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt;. Т.к. &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; в общем случае не является двудольным, для решения этой задачи можно воспользваться [https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B6%D0%B0%D1%82%D0%B8%D1%8F_%D1%86%D0%B2%D0%B5%D1%82%D0%BA%D0%BE%D0%B2 Алгоритмом Эдмондса для поиска наибольшего паросочетания].&lt;/div&gt;</summary>
		<author><name>Cczy</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:1-A-general-graph-G-with-a-3-regular-factor-2-A-general-graph-G-with-an-f-factor_(1).png&amp;diff=72077</id>
		<title>Файл:1-A-general-graph-G-with-a-3-regular-factor-2-A-general-graph-G-with-an-f-factor (1).png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:1-A-general-graph-G-with-a-3-regular-factor-2-A-general-graph-G-with-an-f-factor_(1).png&amp;diff=72077"/>
				<updated>2019-12-29T17:38:38Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Cczy</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%BE%D0%B2&amp;diff=72075</id>
		<title>Обсуждение:Факторизация графов</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%BE%D0%B2&amp;diff=72075"/>
				<updated>2019-12-28T15:48:34Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Определение&lt;br /&gt;
|definition = '''&amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-фактор''' — [[Основные определения теории графов|регулярный]] остовный подграф степени &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Если граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; представляет собой сумму &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-факторов, то их объединение называется &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-факторизацией, а сам граф &amp;lt;tex&amp;gt;G&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;
|definition = Пусть задана функция &amp;lt;tex&amp;gt;f : V(G) \rightarrow \mathbb{N}&amp;lt;/tex&amp;gt;, такая что &amp;lt;tex&amp;gt;\forall~v \in V(G):f(v)\leq \text{deg}(v)&amp;lt;/tex&amp;gt;. Тогда остовный подграф &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; в котором степень каждой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; называется '''&amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактором'''.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Задача о поиске произвольного &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактора ==&lt;br /&gt;
&lt;br /&gt;
Пусть дан граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и функция &amp;lt;tex&amp;gt;f : V(G) \rightarrow \mathbb{N}&amp;lt;/tex&amp;gt;. Построим граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; следующим образом. &lt;br /&gt;
# Для каждого ребра &amp;lt;tex&amp;gt;(u,w)\in E(G)&amp;lt;/tex&amp;gt; добавим в граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; две новых вершины &amp;lt;tex&amp;gt;e(u)&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;e(w)&amp;lt;/tex&amp;gt;, соответствующие &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, и соединим их ребром. В результате каждой вершине &amp;lt;tex&amp;gt;v \in V(G)&amp;lt;/tex&amp;gt; будет соответствовать множество &amp;lt;tex&amp;gt;S(v) \subset V(G_f^*)&amp;lt;/tex&amp;gt; такое что &amp;lt;tex&amp;gt;|S(v)|=deg(v)&amp;lt;/tex&amp;gt;; Каждому ребру &amp;lt;tex&amp;gt;(u,w) \in E(G)&amp;lt;/tex&amp;gt; соответствует ребро &amp;lt;tex&amp;gt;(e(u),e(w))&amp;lt;/tex&amp;gt;, причем ни для каких двух ребер из &amp;lt;tex&amp;gt;E(G)&amp;lt;/tex&amp;gt; концы соответствующих им ребер в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; не пересекаются.&lt;br /&gt;
# Для каждой вершины &amp;lt;tex&amp;gt;v\in V(G)&amp;lt;/tex&amp;gt; добавим в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; новые &amp;lt;tex&amp;gt;deg(v)-f(v)&amp;lt;/tex&amp;gt; вершин, образующие множество &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt;. Каждую вершину из &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt; свяжем ребром с каждой вершиной из &amp;lt;tex&amp;gt;S(v)&amp;lt;/tex&amp;gt;. В результате для каждой вершины &amp;lt;tex&amp;gt;v \in V(G)&amp;lt;/tex&amp;gt; Множество &amp;lt;tex&amp;gt;S(v)\cup T(v)&amp;lt;/tex&amp;gt; образует полный двудольный граф. &lt;br /&gt;
&lt;br /&gt;
[[Файл:A-general-graph-G-with-an-f-factor-and-the-corresponding-simple-graph-G-with-a.png|700px|thumb|centre| Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; и соответствующий ему граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement = &lt;br /&gt;
Граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; имеет &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор тогда и только тогда, когда соответствующий данным графу и функции граф &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; имеет совершенное паросочетание.&lt;br /&gt;
|proof = &lt;br /&gt;
&amp;lt;tex&amp;gt;\Rightarrow&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть граф &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; имеет &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактор &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt;. Построим паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; для графа &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; следующим образом:&lt;br /&gt;
# Для каждого ребра &amp;lt;tex&amp;gt;(u,w)\in G_f&amp;lt;/tex&amp;gt; добавим в &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;  соответствующее ему ребро из &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; . Теперь для каждой вершины &amp;lt;tex&amp;gt;v \in V(g)&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt; вершин из множества &amp;lt;tex&amp;gt;S(v)&amp;lt;/tex&amp;gt; покрыты &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; .&lt;br /&gt;
# Для каждой вершины &amp;lt;tex&amp;gt;v \in V(g)&amp;lt;/tex&amp;gt; пусть &amp;lt;tex&amp;gt;R(v)\subset S(v)&amp;lt;/tex&amp;gt; - множество вершин еще не покрытых &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;. &amp;lt;tex&amp;gt;R(v)\cup T(v)&amp;lt;/tex&amp;gt; является полным двудольным графом, причем размер каждой из долей равен &amp;lt;tex&amp;gt;deg(v)-f(v)&amp;lt;/tex&amp;gt;, следовательно этот граф имеет совершенное паросочетание &amp;lt;tex&amp;gt;M_v&amp;lt;/tex&amp;gt;. Добавим каждое ребро из &amp;lt;tex&amp;gt;M_v&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;.&lt;br /&gt;
В результате каждая вершина в &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; покрыта &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, следовательно &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; является совершенным паросочетанием.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\Leftarrow&amp;lt;/tex&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; имеет совершенное паросочетание &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;. Для каждой вершины &amp;lt;tex&amp;gt;v\in V(G)&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt; является независимым множеством и полностью покрыто &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt;, следовательно множество &amp;lt;tex&amp;gt;R(v)\subset S(v)&amp;lt;/tex&amp;gt; покрыто ребрами, концы которых лежат в &amp;lt;tex&amp;gt;T(v)&amp;lt;/tex&amp;gt;, а значит каждая вершина из &amp;lt;tex&amp;gt;S(v)\setminus R(v)&amp;lt;/tex&amp;gt; покрыта ребром, второй конец которого принадлежит &amp;lt;tex&amp;gt;S(w) : w \in V(G)&amp;lt;/tex&amp;gt;, причем &amp;lt;tex&amp;gt;|S(v)\setminus R(v)| = deg(v)-(deg(v)-f(v))=f(v)&amp;lt;/tex&amp;gt;. Поэтому если мы добавим в &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; все ребра соответствующие ребрам из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; покрывающим &amp;lt;tex&amp;gt;S(v)\setminus R(v) : v \in V(G)&amp;lt;/tex&amp;gt;, то есть все ребра из &amp;lt;tex&amp;gt;M&amp;lt;/tex&amp;gt; концы которых лежат в множествах  &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, то степень каждой вершины &amp;lt;tex&amp;gt;v \in G_f&amp;lt;/tex&amp;gt; будет равна &amp;lt;tex&amp;gt;f(v)&amp;lt;/tex&amp;gt;, а значит &amp;lt;tex&amp;gt;G_f&amp;lt;/tex&amp;gt; будет являться &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактором.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Из доказательства напрямую следует, что задача о поиске произвольного &amp;lt;tex&amp;gt;f&amp;lt;/tex&amp;gt;-фактора графа &amp;lt;tex&amp;gt;G&amp;lt;/tex&amp;gt; сводится к поиску совершенного паросочетания в графе &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt;. Т.к. &amp;lt;tex&amp;gt;G^*&amp;lt;/tex&amp;gt; в общем случае не является двудольным, для решения этой задачи можно воспользваться [https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%B6%D0%B0%D1%82%D0%B8%D1%8F_%D1%86%D0%B2%D0%B5%D1%82%D0%BA%D0%BE%D0%B2 Алгоритмом Эдмондса для поиска наибольшего паросочетания].&lt;/div&gt;</summary>
		<author><name>Cczy</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:A-general-graph-G-with-an-f-factor-and-the-corresponding-simple-graph-G-with-a.png&amp;diff=72074</id>
		<title>Файл:A-general-graph-G-with-an-f-factor-and-the-corresponding-simple-graph-G-with-a.png</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:A-general-graph-G-with-an-f-factor-and-the-corresponding-simple-graph-G-with-a.png&amp;diff=72074"/>
				<updated>2019-12-28T15:42:26Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: Пример графа G*&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Пример графа G*&lt;/div&gt;</summary>
		<author><name>Cczy</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=67717</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=67717"/>
				<updated>2018-12-09T07:52:23Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Cczy&amp;diff=67716</id>
		<title>Участник:Cczy</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Cczy&amp;diff=67716"/>
				<updated>2018-12-08T22:40:20Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: Новая страница: «Захар Жуков, группа M3136»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Захар Жуков, группа M3136&lt;/div&gt;</summary>
		<author><name>Cczy</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=67715</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=67715"/>
				<updated>2018-12-08T22:14:10Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Примеры решения задач */&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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67714</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=67714"/>
				<updated>2018-12-08T21:52:22Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67713</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=67713"/>
				<updated>2018-12-08T21:45:47Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67712</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=67712"/>
				<updated>2018-12-08T21:37:35Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Доказательство корректности */&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; S(P)\over{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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
S(P)\over{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; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{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; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; 1\over{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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67711</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=67711"/>
				<updated>2018-12-08T21:34:50Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &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; S(P)\over{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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
S(P)\over{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; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{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; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; 1\over{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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67710</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=67710"/>
				<updated>2018-12-08T21:02:14Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Доказательство корректности */&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;
Докажем, что с помощью данного алгоритма действительно можно получать случайный комбинаторный размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;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; S(P)\over{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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
S(P)\over{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; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{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; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Результат работы алгоритма является префиксом размера &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; S(result)=1 &amp;lt;/tex&amp;gt;). Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{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;
Рассмотрим алгоритм получения случайного битового вектора. В битовом векторе может находиться только два типа элементов: &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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67709</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=67709"/>
				<updated>2018-12-08T21:00:26Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Доказательство корректности */&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;
Докажем, что с помощью данного алгоритма действительно можно получать случайный комбинаторный размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;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; S(P)\over{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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
S(P)\over{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; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{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; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Результат работы алгоритма является префиксом размера &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; S(result)=1 &amp;lt;/tex&amp;gt;). Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{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;
Рассмотрим алгоритм получения случайного битового вектора. В битовом векторе может находиться только два типа элементов: &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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67708</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=67708"/>
				<updated>2018-12-08T20:36:46Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Описание алгоритма */&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; S(P)\over{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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
S(P)\over{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; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{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; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Результат работы алгоритма является префиксом размера &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; S(result)=1 &amp;lt;/tex&amp;gt;). Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{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;
Рассмотрим алгоритм получения случайного битового вектора. В битовом векторе может находиться только два типа элементов: &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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67707</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=67707"/>
				<updated>2018-12-08T20:36:05Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Доказательство корректности */&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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex dpi = &amp;quot;120&amp;quot;&amp;gt; S(P)\over{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;
*Любой комбинаторный объект имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &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; S(P)\over{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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; &lt;br /&gt;
S(P)\over{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; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{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; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Следовательно предположение индукции верно для всех возможных префиксов любой длины.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Результат работы алгоритма является префиксом размера &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; S(result)=1 &amp;lt;/tex&amp;gt;). Из чего по доказанной лемме следует, что вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{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;
Рассмотрим алгоритм получения случайного битового вектора. В битовом векторе может находиться только два типа элементов: &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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67706</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=67706"/>
				<updated>2018-12-08T20:24:20Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Доказательство корректности */&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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex dpi = &amp;quot;120&amp;quot;&amp;gt; S(P)\over{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;
*Любой комбинаторный объект имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &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; S(P)\over{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;. Вероятность получить некоторый префикс &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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; S(P)\over{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; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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;
=== Битовые вектора ===&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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67705</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=67705"/>
				<updated>2018-12-08T20:07:34Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex dpi = &amp;quot;120&amp;quot;&amp;gt; S(P)\over{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;
*Любой комбинаторный объект имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности ==&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id=идентификатор (необязательно), пример: proposal1. &lt;br /&gt;
|author=Автор утверждения (необязательно)&lt;br /&gt;
|about=О чем утверждение (необязательно)&lt;br /&gt;
|statement=утверждение&lt;br /&gt;
|proof=доказательство (необязательно)&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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67704</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=67704"/>
				<updated>2018-12-08T20:05:31Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Доказательство корректности */&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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex dpi = &amp;quot;120&amp;quot;&amp;gt; S(P)\over{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;
*Любой комбинаторный объект имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{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;
Рассмотрим алгоритм получения случайного битового вектора. В битовом векторе может находиться только два типа элементов: &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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67703</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=67703"/>
				<updated>2018-12-08T20:03:37Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex dpi = &amp;quot;120&amp;quot;&amp;gt; S(P)\over{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;
*Любой комбинаторный объект имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67702</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=67702"/>
				<updated>2018-12-08T19:47:39Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Доказательство корректности */&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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex dpi = &amp;quot;120&amp;quot;&amp;gt; S(P)\over{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;
*Любой комбинаторный объект имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67699</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=67699"/>
				<updated>2018-12-08T19:19:15Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex dpi = &amp;quot;120&amp;quot;&amp;gt; S(P)\over{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;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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}\left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0&amp;diff=67694</id>
		<title>Дискретная математика</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%94%D0%B8%D1%81%D0%BA%D1%80%D0%B5%D1%82%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0&amp;diff=67694"/>
				<updated>2018-12-08T17:43:15Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Генерация комбинаторных объектов */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Категория:Дискретная математика и алгоритмы]]&lt;br /&gt;
Убедительная просьба читать [[Обсуждение:Дискретная_математика_и_алгоритмы | правила оформления вики-конспектов]].&lt;br /&gt;
&lt;br /&gt;
Символом &amp;lt;tex&amp;gt; \star &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;
*[[Транзитивное отношение]]&lt;br /&gt;
*[[Отношение порядка]]&lt;br /&gt;
*[[Изоморфизмы упорядоченных множеств]]&amp;lt;tex&amp;gt;^\star&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;
*[[Побитовые операции]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Суперпозиции]]&lt;br /&gt;
*[[ДНФ]]&lt;br /&gt;
*[[Сокращенная и минимальная ДНФ | Сокращенная и минимальная ДНФ, минимизация ДНФ методами гиперкубов, карт Карно, Квайна]]&lt;br /&gt;
*[[КНФ]]&lt;br /&gt;
*[[2-SAT]]&lt;br /&gt;
*[[XOR-SAT]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Специальные формы КНФ|Специальные формы КНФ: КНФ в форме Хорна и КНФ в форме Крома]]&lt;br /&gt;
*[[Полином Жегалкина | Полином Жегалкина, преобразование Мёбиуса]]&lt;br /&gt;
*[[Полные системы функций. Теорема Поста о полной системе функций]]&lt;br /&gt;
*[[Представление функции класса DM с помощью медианы]]&lt;br /&gt;
*[[Пороговая функция]]&lt;br /&gt;
*[[Троичная логика]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Схемы из функциональных элементов ==&lt;br /&gt;
*[[Реализация булевой функции схемой из функциональных элементов]]&lt;br /&gt;
*[[Простейшие методы синтеза схем из функциональных элементов]]&lt;br /&gt;
*[[Метод Лупанова синтеза схем]]&lt;br /&gt;
*[[Cумматор]]&lt;br /&gt;
*[[Каскадный сумматор]]&lt;br /&gt;
*[[Двоичный каскадный сумматор]]&lt;br /&gt;
*[[Троичный сумматор]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Реализация вычитания сумматором]]&lt;br /&gt;
*[[Матричный умножитель]]&lt;br /&gt;
*[[Дерево Уоллеса]]&lt;br /&gt;
*[[Контактная схема]]&lt;br /&gt;
*[[Триггеры]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
*[[Квантовые гейты]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Представление информации ==&lt;br /&gt;
*[[Кодирование информации]]&lt;br /&gt;
*[[Представление целых чисел: прямой код, код со сдвигом, дополнительный код]]&lt;br /&gt;
*[[Представление вещественных чисел]]&lt;br /&gt;
*[[Представление символов, таблицы кодировок]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Алгоритмы сжатия ==&lt;br /&gt;
* [[Алгоритм Хаффмана]]&lt;br /&gt;
* [[Оптимальное хранение словаря в алгоритме Хаффмана]]&lt;br /&gt;
* [[Алгоритм Хаффмана за O(n)]]&lt;br /&gt;
* [[Алгоритм Ху-Таккера]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Неравенство Крафта]]&lt;br /&gt;
* [[Неравенство Макмиллана]]&lt;br /&gt;
* [[Код Шеннона]]&lt;br /&gt;
* [[Оптимальный префиксный код с длиной кодового слова не более L бит]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритмы LZ77 и LZ78]]&lt;br /&gt;
* [[Алгоритм LZW]]&lt;br /&gt;
* [[Алгоритм LZSS]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Алгоритм LZMA]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;&lt;br /&gt;
* [[Преобразование Барроуза-Уиллера | Преобразование Барроуза-Уиллера и обратное ему]]&lt;br /&gt;
* [[Преобразование MTF]]&lt;br /&gt;
* [[Расстояние Хэмминга]]&lt;br /&gt;
* [[Избыточное кодирование, код Хэмминга]]&lt;br /&gt;
* [[Гамма-, дельта- и омега-код Элиаса]]&amp;lt;tex&amp;gt;^\star&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;
* [[Коды антигрея]]&lt;br /&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;
* [[Получение следующего объекта]]&lt;br /&gt;
* [[Получение предыдущего объекта]]&amp;lt;tex&amp;gt;^\star&amp;lt;/tex&amp;gt;  &lt;br /&gt;
* [[Метод генерации случайной перестановки, алгоритм Фишера-Йетса]]&lt;br /&gt;
* [[Методы генерации случайного сочетания]]&amp;lt;tex&amp;gt;^\star&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;
* [[Числа Стирлинга первого рода]]&lt;br /&gt;
* [[Числа Стирлинга второго рода]]&lt;br /&gt;
* [[Символ Похгаммера]]&lt;br /&gt;
* [[Числа Белла]]&lt;br /&gt;
* [[Числа Эйлера I и II рода | Числа Эйлера первого и второго рода. Подъемы в перестановках]]&amp;lt;tex&amp;gt;^\star&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;
* [[Теорема Кэли]]&lt;br /&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;
* [[Производящие функции нескольких переменных]]&lt;br /&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;
* [[Уравнение Лагранжа и теорема Лагранжа]]&lt;br /&gt;
*[[Асимптотика коэффициентов функций, связанных между собой уравнением Лагранжа]]&lt;/div&gt;</summary>
		<author><name>Cczy</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=67693</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=67693"/>
				<updated>2018-12-08T17:39:32Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Разбиения на множества */&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 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{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;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=1}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67692</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=67692"/>
				<updated>2018-12-08T17:23:27Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Правильные скобочные последовательности */&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 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{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;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=1}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67691</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=67691"/>
				<updated>2018-12-08T17:14:19Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Доказательство корректности */&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 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{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;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , следовательно вероятность получить префикс &amp;lt;tex&amp;gt; P' &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=1}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67690</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=67690"/>
				<updated>2018-12-08T17:10:48Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Доказательство корректности */&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 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{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;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=1}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67689</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=67689"/>
				<updated>2018-12-08T17:09:39Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &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 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=1}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67688</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=67688"/>
				<updated>2018-12-08T15:54:43Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &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 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=1}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67687</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=67687"/>
				<updated>2018-12-08T15:51:30Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Разбиение на случайное число подмножеств */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=1}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67684</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=67684"/>
				<updated>2018-12-08T15:48:57Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Доказательство корректности */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(P)\over{S(\varnothing)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; S(P)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; S(P)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; S(P)\over{C(n)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P')\over{S(P)} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; S(P')\over{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; n &amp;lt;/tex&amp;gt; и для любого такого префикса существует только один комбинаторный объект размера размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; , следовательно вероятность получения одинакова для всех различных результатов и равна &amp;lt;tex&amp;gt; 1\over{C(n)} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=0}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67683</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=67683"/>
				<updated>2018-12-08T15:38:51Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Правильные скобочные последовательности */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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;j&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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=0}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67682</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=67682"/>
				<updated>2018-12-08T15:24:54Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Разбиение на  k  подмножеств */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=0}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67681</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=67681"/>
				<updated>2018-12-08T15:16:48Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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;
   '''for''' 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=0}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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>Cczy</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=67680</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=67680"/>
				<updated>2018-12-08T14:58:30Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Разбиение на случайное число подмножеств */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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;
   '''for''' 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=0}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; 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;/div&gt;</summary>
		<author><name>Cczy</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=67679</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=67679"/>
				<updated>2018-12-08T14:56:50Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Разбиение на  k  подмножеств */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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;
   '''for''' 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=0}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; n &amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt;&lt;br /&gt;
подмножеств.&lt;/div&gt;</summary>
		<author><name>Cczy</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=67678</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=67678"/>
				<updated>2018-12-08T14:55:18Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Разбиения на множества */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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; k &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''for''' 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=0}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop i}\rbrace &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; n &amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt;&lt;br /&gt;
подмножеств.&lt;/div&gt;</summary>
		<author><name>Cczy</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=67677</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=67677"/>
				<updated>2018-12-08T14:50:30Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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; k &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''for''' 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=0}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop ш}\rbrace &amp;lt;/tex&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Cczy</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=67676</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=67676"/>
				<updated>2018-12-08T14:46:26Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Разбиение на случайное число подмножеств */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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; k &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''for''' 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=0}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt; \lbrace{n\atop ш}\rbrace &amp;lt;/tex&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Cczy</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=67675</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=67675"/>
				<updated>2018-12-08T14:45:34Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Разбиения на множества */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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; k &amp;lt;/tex&amp;gt; {{---}} количество элементов в множестве, &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''for''' 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) + 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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop k}\rbrace&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_{i=0}^n \left\{{n\atop i}\right\}&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n\atop ш}\rbrace&amp;lt;/tex&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Cczy</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=67674</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=67674"/>
				<updated>2018-12-08T14:41:10Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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; n &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''for''' 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) + O(n^2) &amp;lt;/tex&amp;gt; на преподсчет чисел Стирлинга второго рода(если предпосчитать их динамически).&lt;/div&gt;</summary>
		<author><name>Cczy</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=67673</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=67673"/>
				<updated>2018-12-08T14:27:34Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., 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; n &amp;lt;/tex&amp;gt; {{---}} число подмножеств на которые нужно разбить исходное множество. &amp;lt;/font&amp;gt;&lt;br /&gt;
   l = 0&lt;br /&gt;
   m = 0&lt;br /&gt;
   '''for''' 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) + O(n^2) &amp;lt;/tex&amp;gt; на преподсчет чисел Стирлинга второго рода(если предпосчитать их динамически).&lt;/div&gt;</summary>
		<author><name>Cczy</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=67672</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=67672"/>
				<updated>2018-12-08T13:56:46Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Разбиения на множества */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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''' randomObject(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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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, ..., B_{k-m}\} &amp;lt;/tex&amp;gt;).&lt;/div&gt;</summary>
		<author><name>Cczy</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=67671</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=67671"/>
				<updated>2018-12-08T13:46:54Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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''' randomObject(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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt;i, j| 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_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; (k-m)\cdot &amp;lt;/tex&amp;gt;&amp;lt;tex dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&amp;lt;/tex&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Cczy</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=67670</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=67670"/>
				<updated>2018-12-08T13:35:45Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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''' randomObject(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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt; 1 &amp;lt;= i &amp;lt; j &amp;lt;= k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m}\rbrace&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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l-1\atop k-m-1}\rbrace&amp;lt;/tex&amp;gt;.&lt;/div&gt;</summary>
		<author><name>Cczy</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=67669</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=67669"/>
				<updated>2018-12-08T13:14:34Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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''' randomObject(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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt; 1 &amp;lt;= i &amp;lt; j &amp;lt;= k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_i &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 dpi = &amp;quot;180&amp;quot;&amp;gt;\lbrace{n-l\atop k-m}\rbrace&amp;lt;/tex&amp;gt; (т.е [[Числа Стирлинга второго рода|числу Стирлинга второго рода]]).&lt;/div&gt;</summary>
		<author><name>Cczy</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=67668</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=67668"/>
				<updated>2018-12-08T12:47:12Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Разбиение на  k  подмножеств */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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''' randomObject(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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке (т.е. чтобы для любых &amp;lt;tex&amp;gt; 1 &amp;lt;= i &amp;lt; j &amp;lt;= k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt;).&lt;/div&gt;</summary>
		<author><name>Cczy</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=67667</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=67667"/>
				<updated>2018-12-08T12:46:46Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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''' randomObject(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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + 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, ..., 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, ..., B_k\} &amp;lt;/tex&amp;gt; с равным распределением вероятности.&lt;br /&gt;
Будем строить разбиение таким образом, чтобы в результате подмножества &amp;lt;tex&amp;gt; \{B_1, B_2, ..., B_k\} &amp;lt;/tex&amp;gt; оказались отсортированы в лексикографическом порядке(т.е. чтобы для любых &amp;lt;tex&amp;gt; 1 &amp;lt;= i &amp;lt; j &amp;lt;= k &amp;lt;/tex&amp;gt; наименьший элемент &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt; был меньше наименьшего элемента &amp;lt;tex&amp;gt; B_i &amp;lt;/tex&amp;gt;).&lt;/div&gt;</summary>
		<author><name>Cczy</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=67665</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=67665"/>
				<updated>2018-12-07T22:47:41Z</updated>
		
		<summary type="html">&lt;p&gt;Cczy: /* Правильные скобочные последовательности */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition = Необходимо сгенерировать случайный комбинаторный объект размера &amp;lt;tex&amp;gt; n &amp;lt;/tex&amp;gt; с равномерным распределением вероятности, если в наличии есть функция для генерации случайного числа в заданном интервале.&lt;br /&gt;
}}&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; B = \{b_1, b_2 ..., 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;
Докажем по индукции, что вероятность получить любой перфикс &amp;lt;tex&amp;gt; P &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &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; - число различных комбинаторных обьектов с таким префиксом.&lt;br /&gt;
*Любой комбинаторный объеут имеет пустой перфикс, следовательно &amp;lt;tex&amp;gt; S(\varnothing)=C(n) &amp;lt;/tex&amp;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; S(\varnothing)\over{S(P)} &amp;lt;/tex&amp;gt;, что равно &amp;lt;tex&amp;gt; C(n)\over{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; l &amp;lt;/tex&amp;gt; равна  &amp;lt;tex&amp;gt; C(n)\over{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; P' &amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; l+1 &amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt; C(n)\over{S(P)} &amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt;\cdot&amp;lt;/tex&amp;gt;&amp;lt;tex&amp;gt; S(P)\over{S(P')} &amp;lt;/tex&amp;gt; , что равно &amp;lt;tex&amp;gt; C(n)\over{S(P')} &amp;lt;/tex&amp;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; 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;
Рассмотрим &amp;quot;полуправильные&amp;quot; скобочные последовательности т.е. такие что всякой закрывающей скобке соответствует парная открывающая, но не все открытые скобки закрыты. Такую последовтеьность можно охарактеризовать двумя числами: &amp;lt;tex&amp;gt; l &amp;lt;/tex&amp;gt; — длина скобочной последовательности и &amp;lt;tex&amp;gt; b &amp;lt;/tex&amp;gt; — баланс (т.е. разность между количеством открывающих и закрывающих скобок). Заметим что любой префикс правильной скобочной последовательности является &amp;quot;полупраильной&amp;quot; скобочной последовательностью, и что для любого префикса &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;quot;полуправильных&amp;quot; скобочных последовательностей длины &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; number(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; number[0][0] = 1 &amp;lt;/tex&amp;gt;, все остальные &amp;lt;tex&amp;gt; number[0][b] = 0 &amp;lt;/tex&amp;gt;. Пусть теперь &amp;lt;tex&amp;gt; i &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;number[l][b] = number[l-1][b-1] + number[l-1][b+1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(считается, что все значения &amp;lt;tex&amp;gt; number[l][b] &amp;lt;/tex&amp;gt; при отрицательном &amp;lt;tex&amp;gt;j&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 = number[n - l][b] &amp;lt;/tex&amp;gt;) , будет разбиваться на два диапазона размерами &amp;lt;tex&amp;gt; number[n - l - 1][b + 1] &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; number[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''' randomObject(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 = number[n - l][b] &lt;br /&gt;
     r = random(1, s)&lt;br /&gt;
      '''if''' number[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) + O(n^2) &amp;lt;/tex&amp;gt; на преподсчет.&lt;/div&gt;</summary>
		<author><name>Cczy</name></author>	</entry>

	</feed>