Задача о наибольшей общей палиндромной подпоследовательности — различия между версиями
Oxygen3 (обсуждение | вклад) |
м (rollbackEdits.php mass rollback) |
||
(не показано 9 промежуточных версий 5 участников) | |||
Строка 1: | Строка 1: | ||
'''[[Задача о наибольшей общей подпоследовательности]]''' (англ. ''longest common subsequence (LCS)'') {{---}} классическая и хорошо изученная проблема. | '''[[Задача о наибольшей общей подпоследовательности]]''' (англ. ''longest common subsequence (LCS)'') {{---}} классическая и хорошо изученная проблема. | ||
− | '''[[Задача о наибольшей подпоследовательности-палиндроме]]''' (англ. ''longest palindromic subsequence (LPS)'') - также хорошо изучена. | + | '''[[Задача о наибольшей подпоследовательности-палиндроме]]''' (англ. ''longest palindromic subsequence (LPS)'') {{---}} также хорошо изучена. |
− | + | Здесь мы рассмотрим задачу, которая объединяет две вышеперечисленные задачи в одну. | |
− | + | {{Определение | |
− | + | |definition = Для последовательности <tex>X</tex>, мы обозначим её подпоследовательность <tex>x_{i}...x_{j}\ (1 \leqslant i \leqslant j \leqslant n)\ </tex> как <tex>X_{i,j}</tex>. Для двух последовательностей <tex>X</tex> и <tex>Y</tex>, если общая подпоследовательность <tex>Z</tex> последовательностей <tex>X</tex> и <tex>Y</tex> является палиндромом, то <tex>Z</tex> называется '''общей подпалиндромной подпоследовательностью''' (англ. ''common palindromic subsequence''). Общая подпалиндромная последовательность, имеющая максимальную длину, называется '''наибольшей общей подпалиндромной подпоследовательностью''' (англ. ''longest common palindromic subsequence (LCPS)'') и мы обозначим её как <tex>LCPS(X,Y)</tex>. | |
− | {{ | + | }}{{Задача |
− | |definition = Для последовательности <tex>X</tex>, мы обозначим | + | |definition = '''Наибольшая общая подпалиндромная подпоследовательность''' {{---}} задача, являющаяся интересным вариантом классической задачи о поиске наибольшей общей подпоследовательности, которая также накладывает условия, что эта подпоследовательность должна быть палиндромом. |
}} | }} | ||
==Наивное решение== | ==Наивное решение== | ||
Можно придумать такое решение данной задачи: найти наибольшую общую подпоследовательность, в ней найти наибольшую подпалиндромную подпоследовательность. Но, к сожалению, это решение '''неверно'''. | Можно придумать такое решение данной задачи: найти наибольшую общую подпоследовательность, в ней найти наибольшую подпалиндромную подпоследовательность. Но, к сожалению, это решение '''неверно'''. | ||
===Контрпример=== | ===Контрпример=== | ||
− | Возьмем | + | Возьмем две последовательности <tex>X=[1,\ 2,\ 3,\ 1]</tex> и <tex>Y=[1,\ 1,\ 2,\ 3]</tex>. |
− | Наибольшей общая подпоследовательность данных последовательностей равна <tex>LCS(X,Y) = 1\ 2\ 3</tex> и в ней наибольшая подпалиндромная последовательность имеет длину <tex>1</tex>. | + | Наибольшей общая подпоследовательность данных последовательностей равна <tex>LCS(X,Y) = [1,\ 2,\ 3]</tex> и в ней наибольшая подпалиндромная последовательность имеет длину <tex>1</tex>. |
− | Но очевидно, что на самом деле последовательность <tex>Z=1\ 1</tex> является наибольшим общей палиндромной подпоследовательностью <tex>X</tex> и <tex>Y</tex> и имеет длину <tex>2</tex>. | + | Но очевидно, что на самом деле последовательность <tex>Z=[1,\ 1]</tex> является наибольшим общей палиндромной подпоследовательностью <tex>X</tex> и <tex>Y</tex> и имеет длину <tex>2</tex>. |
− | == | + | ==Решение с помощью динамического программирования== |
− | Заметим, что в качестве подзадач для <tex>LCPS</tex>, в которых мы можем посчитать ответ, логично взять подпоследовательность от <tex>X</tex> и от <tex>Y</tex>. Основываясь на этом наблюдении мы сформулируем следующую теорему, которая доказывает оптимальную подструктуру свойств задачи <tex>LCPS</tex>. | + | Заметим, что в качестве подзадач для <tex>LCPS</tex>, в которых мы можем посчитать ответ, логично взять подпоследовательность от <tex>X</tex> и от <tex>Y</tex>. Основываясь на этом наблюдении мы сформулируем следующую теорему, которая доказывает оптимальную подструктуру свойств задачи <tex>LCPS</tex>, что даст возможность воспользоваться идеей [[Динамическое программирование | динамического программирования]]. |
{{Теорема | {{Теорема | ||
− | |statement=Пусть <tex>X</tex> и <tex>Y</tex> - две последовательности длин <tex>n</tex> и <tex>m</tex> соответственно, а <tex>X_{i,j}</tex> и <tex>Y_{ | + | |statement=Пусть <tex>X</tex> и <tex>Y</tex> {{---}} две последовательности длин <tex>n</tex> и <tex>m</tex> соответственно, а <tex>X_{i,j}</tex> и <tex>Y_{k,l}</tex> {{---}} две подпоследовательности последовательностей <tex>X</tex> и <tex>Y</tex> соответственно. Пусть <tex>Z = z_{1}z_{2}...z_{u}</tex> {{---}} наибольшая общая подпалиндромная последовательность двух подпоследовательностей <tex>X_{i,j}</tex> и <tex>Y_{k,l}</tex>. Тогда выполняются следующие утверждения, |
− | #Если <tex>x_i=x_j=y_k=y_l=a</tex> (для произвольного <tex>a</tex>), тогда <tex>z_1=z_u=a</tex> и <tex> | + | |
− | #Если <tex>x_i=x_j=y_k=y_l</tex> не выполняется, то <tex>Z</tex> {{---}} | + | # Если <tex>x_i=x_j=y_k=y_l=a</tex> (для произвольного <tex>a</tex>), тогда <tex>z_1=z_u=a</tex> и <tex>Z_{2, u-1}</tex> {{---}} НОПП от подпоследовательностей <tex>X_{i+1,j-1}</tex> и <tex>Y_{k+1,l-1}</tex>. |
+ | # Если <tex>x_i=x_j=y_k=y_l</tex> не выполняется, то <tex>Z</tex> {{---}} НОПП от подпоследовательностей (<tex>X_{i+1,j}</tex> и <tex>Y_{k,l}</tex>) или (<tex>X_{i,j-1}</tex> и <tex>Y_{k,l}</tex>) или (<tex>X_{i,j}</tex> и <tex>Y_{k+1,l}</tex>) или (<tex>X_{i,j}</tex> и <tex>Y_{k,l-1}</tex>). | ||
}} | }} | ||
На основании теоремы мы напишем следующую рекурсивную формулу для длины наибольшей общей подпалиндромной подпоследовательности: | На основании теоремы мы напишем следующую рекурсивную формулу для длины наибольшей общей подпалиндромной подпоследовательности: | ||
Строка 28: | Строка 29: | ||
<tex> | <tex> | ||
lcps[i,j,k,l] = \left\{\begin{array}{llcl} | lcps[i,j,k,l] = \left\{\begin{array}{llcl} | ||
− | 0&&;&i > j\ | + | 0&&;&i > j\ \lor\ k > l\\ |
− | 1&&;&(i = j)\ | + | 1&&;&(i = j)\ \land\ (k = l)\ \land\ (x_i=x_j=y_k=y_l)\\ |
− | 2+lcps[i+1,j-1,k+1,l-1]&&;&(i < j)\ | + | 2+lcps[i+1,j-1,k+1,l-1]&&;&(i < j)\ \land\ (k < l)\ \land\ (x_i=x_j=y_k=y_l)\\ |
− | \max{(}lcps[i+1,j,k,l],lcps[i,j-1,k,l],&&;&(i \leqslant j)\ | + | \max{(}lcps[i+1,j,k,l],lcps[i,j-1,k,l],&&;&(i \leqslant j)\ \land\ (k \leqslant l)\ \land\ \lnot(x_i=x_j=y_k=y_l)\\ |
− | lcps[i,j,k+1,l],lcps[i,j,k,l-1]) | + | \:\:\:\:\:\:\:\:\:\:\:lcps[i,j,k+1,l],lcps[i,j,k,l-1]) |
\end{array}\right. | \end{array}\right. | ||
</tex> | </tex> | ||
Строка 39: | Строка 40: | ||
===Реализация=== | ===Реализация=== | ||
− | Будем использовать динамику с запоминанием ответа. Оформим решения в виде рекурсивной функции <tex>lcps</tex>, которая возвращает ответ для подзадачи, на которую она была вызвана.<br> В массиве <tex>ans</tex> хранятся ответы для подзадач. До запуска функции <tex>lcps</tex> заполним массив <tex>ans</tex> <tex>-1</tex> и | + | Будем использовать динамику с запоминанием ответа (с мемоизацией). Оформим решения в виде рекурсивной функции <tex>lcps</tex>, которая возвращает ответ для подзадачи, на которую она была вызвана.<br> В массиве <tex>\mathtt{ans}</tex> хранятся ответы для подзадач. До запуска функции <tex>lcps</tex> заполним массив <tex>ans</tex> значением <tex>-1</tex>. Так как каждое значение считается не более одного раза и эта операция происходит за <tex>O(1)</tex>, мы получим асимптотику <tex>O(n^4)</tex>. |
===Псевдокод=== | ===Псевдокод=== | ||
− | '''int''' lcps (i: '''int''', j: '''int''', k: '''int''', l: '''int''') | + | '''int''' lcps(i: '''int''', j: '''int''', k: '''int''', l: '''int''') |
− | '''if''' (ans[i][j][k][l] <tex> \neq </tex> -1) <span style="color:Green">// если | + | '''if''' (ans[i][j][k][l] <tex> \neq </tex> -1) <span style="color:Green">// если значение уже посчитано, то надо его вернуть</span> |
'''return''' ans[i][j][k][l] | '''return''' ans[i][j][k][l] | ||
'''if''' (i > j '''or''' k > l) | '''if''' (i > j '''or''' k > l) | ||
Строка 52: | Строка 53: | ||
ans[i][j][k][l] = 1 | ans[i][j][k][l] = 1 | ||
'''return''' 1 | '''return''' 1 | ||
− | '''else''' | + | '''else''' |
− | + | ans[i][j][k][l] = (2 + lcps(i + 1, j - 1, k + 1, l - 1)) | |
− | '''return''' | + | '''return''' ans[i][j][k][l] |
− | + | ans[i][j][k][l] = max(lcps(i + 1, j, k, l), lcps(i, j - 1, k, l), lcps(i, j, k + 1, l), lcps(i, j, k, l - 1)) | |
− | + | '''return''' ans[i][j][k][l] | |
− | ans[i][j][k][l] | ||
− | |||
==См. также== | ==См. также== | ||
− | + | * [[Задача о наибольшей возрастающей подпоследовательности]] | |
− | * [[Задача о наибольшей | + | * [[Задача о редакционном расстоянии, алгоритм Вагнера-Фишера]] |
− | * [[Задача о | ||
==Источники информации== | ==Источники информации== | ||
* [https://www.academia.edu/2015585/Computing_a_Longest_Common_Palindromic_Subsequence Academia.edu {{---}} Computing a Longest Common Palindromic Subsequence] | * [https://www.academia.edu/2015585/Computing_a_Longest_Common_Palindromic_Subsequence Academia.edu {{---}} Computing a Longest Common Palindromic Subsequence] | ||
+ | |||
+ | [[Категория:Дискретная математика и алгоритмы]] | ||
+ | [[Категория:Динамическое программирование]] | ||
+ | [[Категория:Другие задачи динамического программирования]] | ||
+ | [[Категория:Алгоритмы на строках]] |
Текущая версия на 19:37, 4 сентября 2022
Задача о наибольшей общей подпоследовательности (англ. longest common subsequence (LCS)) — классическая и хорошо изученная проблема.
Задача о наибольшей подпоследовательности-палиндроме (англ. longest palindromic subsequence (LPS)) — также хорошо изучена.
Здесь мы рассмотрим задачу, которая объединяет две вышеперечисленные задачи в одну.
Определение: |
Для последовательности | , мы обозначим её подпоследовательность как . Для двух последовательностей и , если общая подпоследовательность последовательностей и является палиндромом, то называется общей подпалиндромной подпоследовательностью (англ. common palindromic subsequence). Общая подпалиндромная последовательность, имеющая максимальную длину, называется наибольшей общей подпалиндромной подпоследовательностью (англ. longest common palindromic subsequence (LCPS)) и мы обозначим её как .
Задача: |
Наибольшая общая подпалиндромная подпоследовательность — задача, являющаяся интересным вариантом классической задачи о поиске наибольшей общей подпоследовательности, которая также накладывает условия, что эта подпоследовательность должна быть палиндромом. |
Содержание
Наивное решение
Можно придумать такое решение данной задачи: найти наибольшую общую подпоследовательность, в ней найти наибольшую подпалиндромную подпоследовательность. Но, к сожалению, это решение неверно.
Контрпример
Возьмем две последовательности
и .Наибольшей общая подпоследовательность данных последовательностей равна
и в ней наибольшая подпалиндромная последовательность имеет длину .Но очевидно, что на самом деле последовательность
является наибольшим общей палиндромной подпоследовательностью и и имеет длину .Решение с помощью динамического программирования
Заметим, что в качестве подзадач для динамического программирования.
, в которых мы можем посчитать ответ, логично взять подпоследовательность от и от . Основываясь на этом наблюдении мы сформулируем следующую теорему, которая доказывает оптимальную подструктуру свойств задачи , что даст возможность воспользоваться идеейТеорема: |
Пусть и — две последовательности длин и соответственно, а и — две подпоследовательности последовательностей и соответственно. Пусть — наибольшая общая подпалиндромная последовательность двух подпоследовательностей и . Тогда выполняются следующие утверждения,
|
На основании теоремы мы напишем следующую рекурсивную формулу для длины наибольшей общей подпалиндромной подпоследовательности:
Где
— длина наибольшей общей палиндромной подпоследовательности от и . Длина наибольшей общей палиндромной подпоследовательности от последовательностей и будет расположена в . Мы можем вычислить эту длину за время используя динамическое программирование.Реализация
Будем использовать динамику с запоминанием ответа (с мемоизацией). Оформим решения в виде рекурсивной функции
В массиве хранятся ответы для подзадач. До запуска функции заполним массив значением . Так как каждое значение считается не более одного раза и эта операция происходит за , мы получим асимптотику .
Псевдокод
int lcps(i: int, j: int, k: int, l: int) if (ans[i][j][k][l] // если значение уже посчитано, то надо его вернуть return ans[i][j][k][l] if (i > j or k > l) ans[i][j][k][l] = 0 return 0 if (X[i] == X[j] == Y[k] == Y[l]) if (i == j and k == l) ans[i][j][k][l] = 1 return 1 else ans[i][j][k][l] = (2 + lcps(i + 1, j - 1, k + 1, l - 1)) return ans[i][j][k][l] ans[i][j][k][l] = max(lcps(i + 1, j, k, l), lcps(i, j - 1, k, l), lcps(i, j, k + 1, l), lcps(i, j, k, l - 1)) return ans[i][j][k][l]-1)
См. также
- Задача о наибольшей возрастающей подпоследовательности
- Задача о редакционном расстоянии, алгоритм Вагнера-Фишера