<?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=91.108.1.252&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=91.108.1.252&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/91.108.1.252"/>
		<updated>2026-06-09T07:27:54Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%B0_%D0%BF%D0%BE_%D0%BD%D0%BE%D0%BC%D0%B5%D1%80%D1%83&amp;diff=75125</id>
		<title>Получение объекта по номеру</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%B0_%D0%BF%D0%BE_%D0%BD%D0%BE%D0%BC%D0%B5%D1%80%D1%83&amp;diff=75125"/>
				<updated>2020-11-08T13:34:17Z</updated>
		
		<summary type="html">&lt;p&gt;91.108.1.252: /* Битовые вектора */ Исправление опечатки&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Описание алгоритма ==&lt;br /&gt;
Получаем элементы объекта по порядку: сначала определим, какой элемент будет стоять на первом месте, потом на втором и так далее. Считаем, что мы нашли первые &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; элементов объекта. Для всех вариантов элемента, который может стоять на позиции с номером &amp;lt;tex&amp;gt;i+1&amp;lt;/tex&amp;gt;, посчитаем диапазон номеров, который будет соответствовать объектам с данным префиксом. Если искомый номер входит в один из диапазонов, то, очевидно, мы нашли элемент, который должен стоять на месте с номером &amp;lt;tex&amp;gt;i+1&amp;lt;/tex&amp;gt;. Диапазоны номеров не пересекаются, значит на это место больше нельзя поставить никакой другой элемент:&lt;br /&gt;
&lt;br /&gt;
*в начале каждого шага &amp;lt;tex&amp;gt;\mathtt{numOfObject}&amp;lt;/tex&amp;gt; {{---}} номер нужного объекта среди тех, у которых префикс до &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-го элемента лексикографически равен префиксу нашего объекта,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{n}&amp;lt;/tex&amp;gt; {{---}} количество мест в комбинаторном объекте (например, битовый вектор длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;),&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{k}&amp;lt;/tex&amp;gt; {{---}} количество различных элементов, которые могут находиться в данном комбинаторном объекте. Например, для битового вектора &amp;lt;tex&amp;gt;k=2&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;.  Все элементы занумерованы в лексикографическом порядке, начиная с &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Комбинаторные объекты занумерованы с &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;. Переход к нумерации с единицы можно сделать с помощью одной операции декремента перед проходом алгоритма: &lt;br /&gt;
 '''function''' num2object(numOfObject: '''int'''):&lt;br /&gt;
   '''for''' i = 1 '''to''' n                     &lt;br /&gt;
     '''for''' j = 1 '''to''' k                      &lt;br /&gt;
       '''if''' j-й элемент можно поставить на i-e место &lt;br /&gt;
         '''if''' numOfObject &amp;gt;= (количество комбинаторных объектов с префиксом object[1..i-1] и элементом j на месте i)&lt;br /&gt;
           numOfObject -= (количество комбинаторных объектов с префиксом object[1..i-1] и элементом j на месте i)&lt;br /&gt;
         '''else'''&lt;br /&gt;
           object[i] = j&lt;br /&gt;
           break&lt;br /&gt;
   '''return''' object&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;
Рассмотрим алгоритм получения &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ого в лексикографическом порядке битового вектора размера &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
При построении битовых векторов можно не проверять условие возможности постановки какого-то объекта на текущее место. На каждый позиции может стоять один из двух элементов, независимо от того, какие элементы находятся в префиксе. Так как у нас всего два возможных элемента, упростим второй цикл до условия: &lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{bitvector[n]}&amp;lt;/tex&amp;gt; {{---}} искомый битовый вектор,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{numOfBitvector}&amp;lt;/tex&amp;gt; {{---}} номер искомого вектора среди всех битовых векторов,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{pow(2, n)}&amp;lt;/tex&amp;gt; {{---}} &amp;lt;tex&amp;gt;2^{n}&amp;lt;/tex&amp;gt; количество битовых векторов длины &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;,&lt;br /&gt;
 '''vector&amp;lt;int&amp;gt;''' num2bitvector(numOfBitvector: '''int'''):&lt;br /&gt;
   '''for''' i = 1 '''to''' n                                      &lt;br /&gt;
    '''if''' numOfBitvector &amp;gt;= pow(2, (n - i))&lt;br /&gt;
      numOfBitvector -= pow(2, (n - i))&lt;br /&gt;
      bitvector[i] = 1&lt;br /&gt;
    '''else'''&lt;br /&gt;
      bitvector[i] = 0    &lt;br /&gt;
   '''return''' bitvector    &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;n&amp;lt;/tex&amp;gt;. &lt;br /&gt;
Алгоритм эквивалентен переводу числа из десятичной системы в двоичную.&lt;br /&gt;
&lt;br /&gt;
== Перестановки ==&lt;br /&gt;
Рассмотрим алгоритм получения &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;-ой в [[Лексикографический порядок|лексикографическом порядке]] перестановки размера &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Заметим, что всем префиксам на каждом шаге будет соответствовать диапазон номеров одинакового размера, (так как количество всевозможных суффиксов зависит только от длины) то есть можем просто посчитать &amp;quot;количество диапазонов, которые идут до нас&amp;quot; (количество цифр уже полностью занятых перестановками с меньшим номером) за &amp;lt;tex&amp;gt;O(1) &amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{k}&amp;lt;/tex&amp;gt; {{---}} номер искомой последовательности,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{n!}&amp;lt;/tex&amp;gt; {{---}} количество перестановок размера &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{permutation[n]}&amp;lt;/tex&amp;gt; {{---}} искомая перестановка,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{was[n]}&amp;lt;/tex&amp;gt; {{---}} использовали ли мы уже эту цифру в перестановке.&lt;br /&gt;
На &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом шаге:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{alreadyWas}&amp;lt;/tex&amp;gt; {{---}} сколько цифр уже полностью заняты перестановками с меньшим номером,&lt;br /&gt;
*мы должны поставить ту цифру, которая еще полностью не занята, то есть цифру с номером &amp;lt;tex&amp;gt;alreadyWas + 1&amp;lt;/tex&amp;gt;. Среди цифр, которых еще нет в нашем префиксе, считаем, что это цифра &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
На &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;-ом шаге:&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{curFree}&amp;lt;/tex&amp;gt; {{---}} если элемент с номером &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; свободен, то он имеет номер curFree среди всех свободных элементов с &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; по &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
 '''list&amp;lt;int&amp;gt;''' num2permutation(k: '''int'''):&lt;br /&gt;
   '''for''' i = 1 '''to''' n                               &lt;br /&gt;
     alreadyWas = k / (n - i)!      &lt;br /&gt;
     k %= (n - i)!&lt;br /&gt;
     curFree = 0&lt;br /&gt;
     '''for''' j = 1 '''to''' n  &lt;br /&gt;
       '''if''' was[j] == ''false'' &lt;br /&gt;
         curFree++&lt;br /&gt;
         '''if''' curFree == alreadyWas + 1&lt;br /&gt;
           permutation[i] = j&lt;br /&gt;
           was[j] = true&lt;br /&gt;
   '''return''' permutation&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм работает за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;, так как в случае перестановок &amp;lt;tex&amp;gt;n=k&amp;lt;/tex&amp;gt;. Мы можем посчитать все &amp;lt;tex&amp;gt;\mathtt{n!}&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(n) &amp;lt;/tex&amp;gt;. Асимптотику можно улучшить &lt;br /&gt;
до &amp;lt;tex&amp;gt;O(n \log {n}) &amp;lt;/tex&amp;gt;, если использовать структуры данных (например, [[Декартово дерево|декартово дерево]] по неявному ключу), которые позволяют искать &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-й элемент множества и удалять элемент &lt;br /&gt;
множества за &amp;lt;tex&amp;gt;O( \log {n}) &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Сочетания ==&lt;br /&gt;
На каждой итерации мы проверяем, входит ли число &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt; в искомое сочетание. Если мы хотим взять &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt;, то номер перестановки должен быть меньше, чем &amp;lt;tex dpi=140&amp;gt;\binom{n - 1}{k - 1}&amp;lt;/tex&amp;gt;, так как потом надо будет выбрать &amp;lt;tex&amp;gt;k - 1&amp;lt;/tex&amp;gt; элемент из &amp;lt;tex&amp;gt;n - 1&amp;lt;/tex&amp;gt; доступных. Если нет, то будем считать, что &amp;lt;tex dpi=140&amp;gt;\binom{n - 1}{k - 1}&amp;lt;/tex&amp;gt; перестановок, начинающихся с &amp;lt;tex&amp;gt;\mathtt{next}&amp;lt;/tex&amp;gt;, мы пропустили. В обоих случаях рассмотрение текущего числа &amp;lt;tex&amp;gt;next&amp;lt;/tex&amp;gt; мы заканчиваем и переходим к следующему числу. &lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{choose}&amp;lt;/tex&amp;gt; {{---}} искомое сочетание,&lt;br /&gt;
*&amp;lt;tex&amp;gt;\mathtt{C[n][k]}&amp;lt;/tex&amp;gt; {{---}} количество сочетаний из &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; по &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\mathtt{C[n][0] = 1}&amp;lt;/tex&amp;gt;,&lt;br /&gt;
&lt;br /&gt;
 '''list&amp;lt;int&amp;gt;''' num2choose(n, k, m: '''int'''):&lt;br /&gt;
   next = 1&lt;br /&gt;
   '''while''' k &amp;gt; 0&lt;br /&gt;
     '''if''' m &amp;lt; C[n - 1][k - 1]&lt;br /&gt;
       choose.push_back(next)&lt;br /&gt;
       k = k -1&lt;br /&gt;
     '''else'''&lt;br /&gt;
       m -= C[n - 1][k - 1]&lt;br /&gt;
     n = n - 1&lt;br /&gt;
     next = next + 1&lt;br /&gt;
   '''return''' choose&lt;br /&gt;
Асимптотика приведенного алгоритма {{---}} &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;, предподсчет &amp;lt;tex&amp;gt;\mathtt{C[n][k]}&amp;lt;/tex&amp;gt;  {{---}} &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;&lt;br /&gt;
== См. также ==&lt;br /&gt;
*[[Получение номера по объекту|Получение номера по объекту]]&lt;br /&gt;
*[[Получение_предыдущего_объекта#.D0.A1.D0.BF.D0.B5.D1.86.D0.B8.D0.B0.D0.BB.D0.B8.D0.B7.D0.B0.D1.86.D0.B8.D1.8F_.D0.B0.D0.BB.D0.B3.D0.BE.D1.80.D0.B8.D1.82.D0.BC.D0.B0_.D0.B4.D0.BB.D1.8F_.D0.B3.D0.B5.D0.BD.D0.B5.D1.80.D0.B0.D1.86.D0.B8.D0.B8_.D0.BF.D1.80.D0.B5.D0.B4.D1.8B.D0.B4.D1.83.D1.89.D0.B5.D0.B3.D0.BE_.D1.81.D0.BE.D1.87.D0.B5.D1.82.D0.B0.D0.BD.D0.B8.D1.8F|Получение предыдущего сочетания]]&lt;br /&gt;
*[[Получение_следующего_объекта#.D0.A1.D0.BF.D0.B5.D1.86.D0.B8.D0.B0.D0.BB.D0.B8.D0.B7.D0.B0.D1.86.D0.B8.D1.8F_.D0.B0.D0.BB.D0.B3.D0.BE.D1.80.D0.B8.D1.82.D0.BC.D0.B0_.D0.B4.D0.BB.D1.8F_.D0.B3.D0.B5.D0.BD.D0.B5.D1.80.D0.B0.D1.86.D0.B8.D0.B8_.D1.81.D0.BB.D0.B5.D0.B4.D1.83.D1.8E.D1.89.D0.B5.D0.B3.D0.BE_.D1.81.D0.BE.D1.87.D0.B5.D1.82.D0.B0.D0.BD.D0.B8.D1.8F|Генерация следующего сочетания]]&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
*Программирование в алгоритмах / С. М. Окулов. — М.: БИНОМ. Лаборатория знаний, 2002. стр.31 - ISBN 5-94774-010-9&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Комбинаторика]]&lt;/div&gt;</summary>
		<author><name>91.108.1.252</name></author>	</entry>

	</feed>