Получение номера по объекту — различия между версиями
| Строка 2: | Строка 2: | ||
| Получим элементы объекта по порядку: сначала определим какой элемент будет стоять на 1-м месте, 2-м и т.д. Пусть мы нашли первые i элементов нашего объекта. Для всех вариантов элемента, который может стоять на (i+1)-ой позиции, посчитаем диапазон номеров, который будет сообветствовать объектам с данным префиксом. Если искомый номер входит в один из диапазонов, то, очевидно, мы нашли элемент, который должени стоять на (i+1)-ом месте. (Диапазоны номеров не пересекаются, значит, на это место больше нельзя поставить никакой другой элемент, соответственно, это единственный элемент, который может стоять на этой позиции). | Получим элементы объекта по порядку: сначала определим какой элемент будет стоять на 1-м месте, 2-м и т.д. Пусть мы нашли первые i элементов нашего объекта. Для всех вариантов элемента, который может стоять на (i+1)-ой позиции, посчитаем диапазон номеров, который будет сообветствовать объектам с данным префиксом. Если искомый номер входит в один из диапазонов, то, очевидно, мы нашли элемент, который должени стоять на (i+1)-ом месте. (Диапазоны номеров не пересекаются, значит, на это место больше нельзя поставить никакой другой элемент, соответственно, это единственный элемент, который может стоять на этой позиции). | ||
| − |    numOfObject=1  | + |    numOfObject=1                              ''// numOfObject {{---}} искомый номер комбинаторного объекта | 
|    '''for'''  i = 1  '''to'''  n  '''do'''                      ''//перебираем элементы комбинаторного объекта'' |    '''for'''  i = 1  '''to'''  n  '''do'''                      ''//перебираем элементы комбинаторного объекта'' | ||
|      '''for'''  j = 1  '''to'''  i-1  '''do'''                      ''//перебираем элементы которые в лексикографическом порядке меньше рассматриваемого'' |      '''for'''  j = 1  '''to'''  i-1  '''do'''                      ''//перебираем элементы которые в лексикографическом порядке меньше рассматриваемого'' | ||
Версия 06:03, 29 октября 2011
Содержание
Общий алгоритм получения номера в лексикографическом порядке по комбинаторному объекту
Получим элементы объекта по порядку: сначала определим какой элемент будет стоять на 1-м месте, 2-м и т.д. Пусть мы нашли первые i элементов нашего объекта. Для всех вариантов элемента, который может стоять на (i+1)-ой позиции, посчитаем диапазон номеров, который будет сообветствовать объектам с данным префиксом. Если искомый номер входит в один из диапазонов, то, очевидно, мы нашли элемент, который должени стоять на (i+1)-ом месте. (Диапазоны номеров не пересекаются, значит, на это место больше нельзя поставить никакой другой элемент, соответственно, это единственный элемент, который может стоять на этой позиции).
 numOfObject=1                              // numOfObject — искомый номер комбинаторного объекта
 for  i = 1  to  n  do                      //перебираем элементы комбинаторного объекта
   for  j = 1  to  i-1  do                      //перебираем элементы которые в лексикографическом порядке меньше рассматриваемого
     if элемент j можно поставить на i-e место
       then numOfObject+=(коллличество комбинаторных объектов с данным префиксом)              
Несложно понять, что корректность алгоритма следует из его построения. Сложность алгоритма , где - сложность вычисления количества комбинаторных объектов с данным префиксом. Основную сложность при построении алгоритмов генерации комбинаторных объектов составляет вычисление количества комбинаторных объектов с данным префиксом. Приведем примеры способов нахождения количества некоторых из комбинаторных объектов.
Перестановки
Рассмотрим алгоритм получения i-ой в лексикографическом порядке перестановки размера n.
— количество перестановок размера n permutation[n] — искомая перестановка was[n] — использовали ли мы уже эту цифру в перестановке for i = 1 to n do //n - количество цифр в перестановке alreadyWas = (numOfPermutation-1) div // сколько цифр уже полностью заняты перестановками с меньшим номером numOfPermutation = ((numOfPermutation-1) mod ) + 1 //сейчас мы должны поставить ту цифру, которая еще полностью не занята, т.е. alreadyWas+1, которая еще не занята for j = 1 to n do if was[j] = false then cntFree++ if cntFree = alreadyWas+1 then ans[i] = j was[j] = true
Данный алгоритм работает за . Мы можем посчитать за . Асимптотику можно улучшить до , если использовать структуры данных, которые позволяют искать i-ый элемент множества и удалять элемент множества за . Например декартово дерево по неявному ключу.
Размещения
Рассмотрим алгоритм получения i-го в лексикографическом порядке размещения
— количество размещений из n по k placement[n] — искомое размещение was[n] — использовали ли мы уже эту цифру в размещении for i = 1 to k do //k - количество цифр в размещении alreadyWas = (numOfPlacement-1) div // сколько цифр уже полностью заняты размещениями с меньшим номером numOfPlacement = ((numOfPlacement-1) mod ) + 1 //сейчас мы должны поставить ту цифру, которая еще полностью не занята, т.е. alreadyWas+1, которая еще не занята for j = 1 to n do if was[j] = false then cntFree++ if cntFree = alreadyWas+1 then ans[i] = j was[j] = true
Сложность алгоритма .
Сочетания
Рассмотрим алгоритм получения i-го в лексикографическом порядке сочетания
— количество сочетаний из n по k combination[n] — искомое сочетание was[n] — использовали ли мы уже эту цифру в сочетании for i = 1 to k do //k - количество цифр в сочетании // вычтем те "группы" где, i-цифра меньше искомой numOfCombination = ((numOfCombination-1) mod ) + 1 //сейчас мы должны поставить ту цифру, которая еще полностью не занята, т.е. alreadyWas+1, которая еще не занята for j = 1 to n do if was[j] = false then cntFree++ if cntFree = alreadyWas+1 then ans[i] = j was[j] = true
Сложность алгоритма .
Битовые вектора
Скобочные последовательности
Разложение на слагаемые
См. также
[Получение номера по объекту|Получение номера по объекту]
