Таблица инверсий — различия между версиями
Megabyte (обсуждение | вклад) |
м (убран wikitex) |
||
| Строка 1: | Строка 1: | ||
| − | < | + | Пусть <tex> P = (p_1,p_2,\dots,p_n)</tex> является [[Действие перестановки на набор из элементов, представление в виде циклов|перестановкой]] чисел <tex> 1, 2,\dots, n</tex>. |
| − | |||
{{Определение | {{Определение | ||
|definition = | |definition = | ||
| − | '''Инверсией''' в перестановке | + | '''Инверсией''' в перестановке <tex>P</tex> называется всякая пара индексов <tex>i, j</tex> такая, что <tex>1\leqslant i<j\leqslant n</tex> и <tex>P[i]>P[j]</tex>. |
}} | }} | ||
{{Определение | {{Определение | ||
|definition = | |definition = | ||
| − | '''Таблицей инверсий''' перестановки | + | '''Таблицей инверсий''' перестановки <tex> P </tex> называют такую последовательность <tex> T = (t_1,t_2,\dots,t_n)</tex>, в которой <tex>t_i</tex> равно числу элементов перестановки <tex> P </tex>, стоящих в <tex> P </tex> левее числа <tex>i</tex> и больших <tex>i</tex>. |
}} | }} | ||
| Строка 21: | Строка 20: | ||
if P[j] > P[i] | if P[j] > P[i] | ||
T[P[i]] = T[P[i]] + 1 | T[P[i]] = T[P[i]] + 1 | ||
| − | Сложность данного алгоритма {{---}} | + | Сложность данного алгоритма {{---}} <tex>O(n^2)</tex>. Уменьшить время работы можно используя [[Дерево отрезков. Построение|дерево отрезков]]. |
| − | Получим из исходной перестановки обратную и запишем её в массив | + | Получим из исходной перестановки обратную и запишем её в массив <tex>M</tex>. Также заведём массив <tex>S</tex> длиной <tex>n</tex>, инициализированный нулями. После обработки <tex>i</tex>-го элемента будем вносить значение 1 в ячейку <tex>S[M[i]]</tex>. Обработку начинаем с последнего элемента и двигаемся к началу. Пусть, функция <tex>Sum(i)</tex> возвращает значение суммы элементов массива <tex>S</tex> от 1 до <tex>i</tex>. Тогда <tex>i</tex>-й элемент таблицы инверсий находится так: |
| − | + | <tex>T[i] = Sum(M[i])</tex> | |
| − | Данная формула даёт правильный ответ, так как | + | Данная формула даёт правильный ответ, так как <tex>S[M[i]]</tex> содержит единицу только в том случае, если мы уже обработали элемент, стоящий в <tex>M[i]</tex>-й позиции. Так как обработка идёт от больших чисел к меньшим, <tex>Sum(M[i])</tex> выдаст нужное нам количество чисел, больших <tex>i</tex> и стоящих в перестановке левее него. |
| − | Функция | + | Функция <tex>Sum</tex> реализуется с помощью [[Дерево отрезков. Построение|дерева отрезков]]. Каждое изменение массива и обращение к функции <tex>Sum</tex> влечёт за собой <tex>\log_2n</tex> операций. Таким образом получаем сложность алгоритма <tex>O(n\log_2n)</tex> |
| − | Также существует достаточно простой алгоритм построения таблицы инверсий с использованием [[Сортировка слиянием|сортировки слиянием]]. Вначале выписываются следующие упорядоченные пары чисел: в | + | Также существует достаточно простой алгоритм построения таблицы инверсий с использованием [[Сортировка слиянием|сортировки слиянием]]. Вначале выписываются следующие упорядоченные пары чисел: в <tex>i</tex>-ой паре на первом месте стоит <tex>i</tex>-й элемент перестановки, а на втором {{---}} 0. Далее применяется [[Сортировка слиянием|сортировка слиянием]], при чем при выписывании элемента из второй цепочки упорядоченных пар, число на второй позиции в данном элементе увеличивается на количество элементов, оставшихся в первой цепочке. В конце сортировки получим цепочку упорядоченных пар. Выписывая вторые элементы данных упорядоченных пар, получим искомую таблицу инверсий. Сложность данного алгоритма совпадает со сложностью [[Сортировка слиянием|сортировки слиянием]] и составляет <tex>O(n\log_2n)</tex>. |
= Алгоритм восстановления = | = Алгоритм восстановления = | ||
| − | Для восстановления таблицы перестановки из таблицы инверсий создаем таблицу, которую будем расширять, по мере добавления в неё чисел. Добавляем в эту таблицу число | + | Для восстановления таблицы перестановки из таблицы инверсий создаем таблицу, которую будем расширять, по мере добавления в неё чисел. Добавляем в эту таблицу число <tex>i</tex> (где <tex>i</tex> от <tex>n</tex> до 1) на позицию <tex>k+1</tex>, где <tex>k</tex> - число в таблице инверсий на <tex>i</tex>-том месте. Данный алгоритм довольно прост в реализации, но без использования дополнительных структур данных, имеет сложность <tex>O(n^2)</tex>, т. к. для вставки элемента в определённую позицию, требуется порядка <tex>n</tex> перестановок элементов. |
| − | Приведём алгоритм восстановления с использованием [[Сортировка слиянием|сортировки слиянием]], имеющий сложность | + | Приведём алгоритм восстановления с использованием [[Сортировка слиянием|сортировки слиянием]], имеющий сложность <tex>O(n\log_2n)</tex>. |
| − | Пусть | + | Пусть <tex>\alpha</tex> и <tex>\beta</tex> - цепочки упорядоченных пар целых неотрицательных чисел <tex>[m_1, n_1]\dots[m_k, n_k]</tex>. Рассмотрим двоичную операцию <tex>\circ</tex>, рекурсивно определенную на парах таких цепочек следующим образом: |
$([m, n]\alpha)\circ([m', n']\beta)=\left\{\begin{aligned}[] | $([m, n]\alpha)\circ([m', n']\beta)=\left\{\begin{aligned}[] | ||
[m,n](\alpha \circ ([m'-m, n']\beta)), m \le m',\\ | [m,n](\alpha \circ ([m'-m, n']\beta)), m \le m',\\ | ||
| Строка 45: | Строка 44: | ||
\right.$ | \right.$ | ||
| − | Сопоставим каждому элементу таблицы инверсий его номер. Получится множество упорядоченных пар чисел | + | Сопоставим каждому элементу таблицы инверсий его номер. Получится множество упорядоченных пар чисел <tex>[m_1, n_1]\dots[m_k, n_k]</tex>, где <tex>m_i</tex> {{---}} сам элемент, а <tex>n_i</tex> {{---}} его номер. Разобьём данные элементы на пары и произведём с ними операцию <tex>\circ</tex>. Получим некоторое количество цепочек упорядоченных пар. Также разбиваем их на пары и производим операцию <tex>\circ</tex>. Так действуем, пока не останется одна цепочка. Выписывая вторые элементы данных упорядоченных пар в том порядке, в каком они представлены в цепочке, получим первоначальную перестановку. |
| − | Цепочка наподобие | + | Цепочка наподобие <tex>[4, 4][1,3]</tex> представляет "_ _ _ _ 4 _ 3 _ <tex>\infty</tex>", где "_" означает пропуск. Операция <tex>\alpha \circ \beta</tex> вставляет пропуски и заполнения из <tex>\beta</tex> на место пропусков в <tex>\alpha</tex>. |
== Пример == | == Пример == | ||
| − | * | + | * <tex>[4, 1, 6, 3, 2, 2, 1, 1, 1, 0]</tex> - таблица инверсий. |
| + | * <tex>[4,1]\circ[1,2], [6,3]\circ[3,4], [2,5]\circ[2,6], [1,7]\circ[1,8], [1,9]\circ[0,10]</tex> | ||
| + | * <tex>[1,2][2,1]\circ[3,4][2,3], [2,5][0,6]\circ[1,7][0,8], [0,10][0,9]</tex> | ||
| + | * <tex>[1,2][2,1][0,4][2,3]\circ[1,7][0,5][0,6][0,8], [0,10][0,9]</tex> | ||
| + | * <tex>[1,2][0,7][0,5][0,1][0,4][0,6][0,8][0,3]\circ[0,10][0,9]</tex> | ||
| + | * <tex>[0,10][0,2][0,7][0,5][0,1][0,4][0,6][0,8][0,3][0,9]</tex> | ||
| − | + | Получаем перестановку <tex>[10, 2, 7, 5, 1, 4, 6, 8, 3, 9]</tex> | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | Получаем перестановку | ||
= Источники = | = Источники = | ||
* Д. Кнут - Искусство программирования, том 3. | * Д. Кнут - Искусство программирования, том 3. | ||
| − | |||
Версия 13:36, 12 января 2012
Пусть является перестановкой чисел .
| Определение: |
| Инверсией в перестановке называется всякая пара индексов такая, что и . |
| Определение: |
| Таблицей инверсий перестановки называют такую последовательность , в которой равно числу элементов перестановки , стоящих в левее числа и больших . |
Алгоритм построения
Таблицу инверсий тривиально построить по определению. Для каждого элемента перестановки считаем количество элементов, больших данного и стоящих в перестановке левее него. Алгоритм построения в псевдокоде выглядит так:
T[1..n] = 0
For i = 1..n
For j = 1..(i - 1)
if P[j] > P[i]
T[P[i]] = T[P[i]] + 1
Сложность данного алгоритма — . Уменьшить время работы можно используя дерево отрезков.
Получим из исходной перестановки обратную и запишем её в массив . Также заведём массив длиной , инициализированный нулями. После обработки -го элемента будем вносить значение 1 в ячейку . Обработку начинаем с последнего элемента и двигаемся к началу. Пусть, функция возвращает значение суммы элементов массива от 1 до . Тогда -й элемент таблицы инверсий находится так:
Данная формула даёт правильный ответ, так как содержит единицу только в том случае, если мы уже обработали элемент, стоящий в -й позиции. Так как обработка идёт от больших чисел к меньшим, выдаст нужное нам количество чисел, больших и стоящих в перестановке левее него.
Функция реализуется с помощью дерева отрезков. Каждое изменение массива и обращение к функции влечёт за собой операций. Таким образом получаем сложность алгоритма
Также существует достаточно простой алгоритм построения таблицы инверсий с использованием сортировки слиянием. Вначале выписываются следующие упорядоченные пары чисел: в -ой паре на первом месте стоит -й элемент перестановки, а на втором — 0. Далее применяется сортировка слиянием, при чем при выписывании элемента из второй цепочки упорядоченных пар, число на второй позиции в данном элементе увеличивается на количество элементов, оставшихся в первой цепочке. В конце сортировки получим цепочку упорядоченных пар. Выписывая вторые элементы данных упорядоченных пар, получим искомую таблицу инверсий. Сложность данного алгоритма совпадает со сложностью сортировки слиянием и составляет .
Алгоритм восстановления
Для восстановления таблицы перестановки из таблицы инверсий создаем таблицу, которую будем расширять, по мере добавления в неё чисел. Добавляем в эту таблицу число (где от до 1) на позицию , где - число в таблице инверсий на -том месте. Данный алгоритм довольно прост в реализации, но без использования дополнительных структур данных, имеет сложность , т. к. для вставки элемента в определённую позицию, требуется порядка перестановок элементов.
Приведём алгоритм восстановления с использованием сортировки слиянием, имеющий сложность .
Пусть и - цепочки упорядоченных пар целых неотрицательных чисел . Рассмотрим двоичную операцию , рекурсивно определенную на парах таких цепочек следующим образом:
$([m, n]\alpha)\circ([m', n']\beta)=\left\{\begin{aligned}[]
[m,n](\alpha \circ ([m'-m, n']\beta)), m \le m',\\
[m', n'](([m-m'-1, n]\alpha) \circ \beta), m>m'.\\
\end{aligned}
\right.$
Сопоставим каждому элементу таблицы инверсий его номер. Получится множество упорядоченных пар чисел , где — сам элемент, а — его номер. Разобьём данные элементы на пары и произведём с ними операцию . Получим некоторое количество цепочек упорядоченных пар. Также разбиваем их на пары и производим операцию . Так действуем, пока не останется одна цепочка. Выписывая вторые элементы данных упорядоченных пар в том порядке, в каком они представлены в цепочке, получим первоначальную перестановку.
Цепочка наподобие представляет "_ _ _ _ 4 _ 3 _ ", где "_" означает пропуск. Операция вставляет пропуски и заполнения из на место пропусков в .
Пример
- - таблица инверсий.
Получаем перестановку
Источники
- Д. Кнут - Искусство программирования, том 3.