Получение номера по объекту — различия между версиями
| 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
Сложность алгоритма .
Битовые вектора
Скобочные последовательности
Разложение на слагаемые
См. также
[Получение номера по объекту|Получение номера по объекту]
