Получение номера по объекту — различия между версиями
Antonkov (обсуждение | вклад) |
|||
Строка 1: | Строка 1: | ||
− | == | + | == Общий алгоритм получения номера в лексикографическом порядке по комбинаторному объекту == |
− | ''' | + | Получим элементы объекта по порядку: сначала определим какой элемент будет стоять на 1-м месте, 2-м и т.д. Пусть мы нашли первые i элементов нашего объекта. Для всех вариантов элемента, который может стоять на (i+1)-ой позиции, посчитаем диапазон номеров, который будет сообветствовать объектам с данным префиксом. Если искомый номер входит в один из диапазонов, то, очевидно, мы нашли элемент, который должени стоять на (i+1)-ом месте. (Диапазоны номеров не пересекаются, значит, на это место больше нельзя поставить никакой другой элемент, соответственно, это единственный элемент, который может стоять на этой позиции). |
+ | '''for''' i = 1 '''to''' n '''do''' ''//перебираем элементы комбинаторного объекта'' | ||
+ | '''for''' j = 1 '''to''' i-1 '''do''' ''//перебираем элементы которые в лексикографическом порядке меньше рассматриваемого'' | ||
+ | '''if''' элемент j можно поставить на i-e место | ||
+ | '''then ans+=(коллличество комбинаторных объектов с данн if | ||
+ | |||
+ | Несложно понять, что корректность алгоритма следует из его построения. | ||
+ | Сложность алгоритма <tex>O(n^{2}f(1..i)) </tex>, где <tex>f(1..i)</tex> - сложность вычисления количества комбинаторных объектов с данным префиксом. Основную сложность при построении алгоритмов генерации комбинаторных объектов составляет вычисление количества комбинаторных объектов с данным префиксом. Приведем примеры способов нахождения количества некоторых из [[Комбинаторные объекты|комбинаторных объектов]]. | ||
+ | == Перестановки == | ||
+ | Рассмотрим алгоритм получения i-ой в лексикографическом порядке перестановки размера n. | ||
+ | <tex>P_{n} </tex> ''{{---}} количество перестановок размера n | ||
+ | permutation[n] ''{{---}} искомая перестановка'' | ||
+ | was[n] ''{{---}} использовали ли мы уже эту цифру в перестановке'' | ||
+ | '''for''' i = 1 '''to''' n '''do''' ''//n - количество цифр в перестановке'' | ||
+ | alreadyWas = (numOfPermutation-1) div <tex>P_{n-i} </tex> ''// сколько цифр уже полностью заняты перестановками с меньшим номером'' | ||
+ | numOfPermutation = ((numOfPermutation-1) mod <tex>P_{n-i} </tex>) + 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 | ||
− | + | Данный алгоритм работает за <tex>O(n^2) </tex>. Мы можем посчитать <tex>P_{n} </tex> за <tex>O(n) </tex>. Асимптотику можно улучшить | |
+ | до <tex>O(n log {n}) </tex>, если использовать структуры данных, которые позволяют искать i-ый элемент множества и удалять элемент | ||
+ | множества за <tex>O( log {n}) </tex>. Например декартово дерево по неявному ключу. | ||
− | + | == Размещения == | |
+ | Рассмотрим алгоритм получения i-го в лексикографическом порядке размещения <tex> A^k_n </tex> | ||
+ | <tex>A^{k}_{n} </tex> ''{{---}} количество размещений из n по k | ||
+ | placement[n] ''{{---}} искомое размещение'' | ||
+ | was[n] ''{{---}} использовали ли мы уже эту цифру в размещении'' | ||
+ | '''for''' i = 1 '''to''' k '''do''' ''//k - количество цифр в размещении'' | ||
+ | alreadyWas = (numOfPlacement-1) div <tex> A^{k-i}_{n-i} </tex> ''// сколько цифр уже полностью заняты размещениями с меньшим номером'' | ||
+ | numOfPlacement = ((numOfPlacement-1) mod <tex> A^{k-i}_{n-i} </tex>) + 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 | ||
+ | Сложность алгоритма <tex>O(nk) </tex>. | ||
− | + | == Сочетания == | |
− | + | Рассмотрим алгоритм получения i-го в лексикографическом порядке сочетания <tex> С^k_n </tex> | |
− | + | <tex>С^{k}_{n} </tex> ''{{---}} количество сочетаний из n по k | |
− | + | combination[n] ''{{---}} искомое сочетание'' | |
− | + | was[n] ''{{---}} использовали ли мы уже эту цифру в сочетании'' | |
− | + | '''for''' i = 1 '''to''' k '''do''' ''//k - количество цифр в сочетании'' | |
− | + | ''// вычтем те "группы" где, i-цифра меньше искомой'' | |
− | + | numOfCombination = ((numOfCombination-1) mod <tex> A^{k-i}_{n-i} </tex>) + 1 | |
− | + | ''//сейчас мы должны поставить ту цифру, которая еще полностью не занята, т.е. alreadyWas+1, которая еще не занята'' | |
− | == | + | '''for''' j = 1 '''to''' n '''do''' |
− | + | '''if''' was[j] = false | |
− | <tex> | + | '''then ''' cntFree++ |
− | + | '''if''' cntFree = alreadyWas+1 | |
− | + | '''then ''' ans[i] = j | |
− | == | + | was[j] = true |
− | + | Сложность алгоритма <tex>O(nk) </tex>. | |
− | + | == Битовые вектора == | |
− | + | == Скобочные последовательности == | |
− | + | == Разложение на слагаемые == | |
− | == | + | == См. также == |
− | + | [Получение номера по объекту|Получение номера по объекту] | |
− | |||
− | |||
− | == | ||
− | |||
− | [ | ||
[[Категория: Дискретная математика и алгоритмы]] | [[Категория: Дискретная математика и алгоритмы]] | ||
[[Категория: Комбинаторика]] | [[Категория: Комбинаторика]] |
Версия 05:54, 29 октября 2011
Содержание
Общий алгоритм получения номера в лексикографическом порядке по комбинаторному объекту
Получим элементы объекта по порядку: сначала определим какой элемент будет стоять на 1-м месте, 2-м и т.д. Пусть мы нашли первые i элементов нашего объекта. Для всех вариантов элемента, который может стоять на (i+1)-ой позиции, посчитаем диапазон номеров, который будет сообветствовать объектам с данным префиксом. Если искомый номер входит в один из диапазонов, то, очевидно, мы нашли элемент, который должени стоять на (i+1)-ом месте. (Диапазоны номеров не пересекаются, значит, на это место больше нельзя поставить никакой другой элемент, соответственно, это единственный элемент, который может стоять на этой позиции).
for i = 1 to n do //перебираем элементы комбинаторного объекта for j = 1 to i-1 do //перебираем элементы которые в лексикографическом порядке меньше рассматриваемого if элемент j можно поставить на i-e место then ans+=(коллличество комбинаторных объектов с данн if
Несложно понять, что корректность алгоритма следует из его построения. Сложность алгоритма комбинаторных объектов.
, где - сложность вычисления количества комбинаторных объектов с данным префиксом. Основную сложность при построении алгоритмов генерации комбинаторных объектов составляет вычисление количества комбинаторных объектов с данным префиксом. Приведем примеры способов нахождения количества некоторых изПерестановки
Рассмотрим алгоритм получения 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
Сложность алгоритма
.Битовые вектора
Скобочные последовательности
Разложение на слагаемые
См. также
[Получение номера по объекту|Получение номера по объекту]