Задача о наибольшей общей подпоследовательности — различия между версиями
Андрей (обсуждение | вклад) |
Андрей (обсуждение | вклад) |
||
Строка 144: | Строка 144: | ||
<ref>[http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Relation_to_other_problems Wikipedia {{---}} Longest common subsequence problem]</ref> | <ref>[http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Relation_to_other_problems Wikipedia {{---}} Longest common subsequence problem]</ref> | ||
+ | == Решение для случая k строк == | ||
+ | Найдем решение для 3 строк. | ||
+ | {{Задача | ||
+ | |definition = Пусть имеются последовательности <tex> X = \left \langle x_1, x_2, \dots, x_m \right \rangle </tex>, <tex> Y = \left \langle y_1, y_2, \dots, y_n \right \rangle </tex> и <tex>Z = \left \langle z_1, z_2, \dots, z_m \right \rangle</tex>. Необходимо найти <tex>LCS(X,Y,Z)</tex> | ||
+ | }} | ||
+ | Нельзя подсчитать <tex>V = LCS(X,Y)</tex>, а потом <tex>LCS(V,Z)</tex>. Это легко доказывается контрпримером. | ||
+ | Даны три строки: | ||
+ | |||
+ | <tex>X = \left \langle A, B, C, D, E\right \rangle </tex> | ||
+ | |||
+ | <tex>Y = \left \langle D, E, A, B, C\right \rangle </tex> | ||
+ | |||
+ | <tex>Z = \left \langle D, E, F, G, H\right \rangle </tex> | ||
+ | |||
+ | Подсчитаем <tex>V = LCS(X,Y) = \left \langle A, B, C \right \rangle LCS(Z,S3) = \emptyset</tex> | ||
+ | Это неверно, так как <tex>LCS(X,Y,Z) = \left \langle D, E \right \rangle</tex> | ||
+ | |||
+ | {{Теорема | ||
+ | |statement = Пусть имеются последовательности <tex> X = \left \langle x_1, x_2, \dots, x_m \right \rangle </tex>, <tex> Y = \left \langle y_1, y_2, \dots, y_n \right \rangle </tex> и <tex> Z = \left \langle z_1, z_2, \dots, z_k \right \rangle </tex>, а <tex> V = \left \langle v_1, v_2, \dots, v_h \right \rangle</tex> — их <tex>LCS</tex>. | ||
+ | # Если <tex>z_k = x_m = y_n</tex>, то <tex>z_k = x_m = y_n = v_h</tex> и <tex> V_{h - 1} </tex> — <tex>LCS(X_{m - 1},Y_{n - 1},Z_{k - 1})</tex> | ||
+ | # Если <tex>z_k \neq x_m \neq y_n</tex>, то из <tex>z_k \neq v_h</tex> следует, что <tex>V</tex> — <tex>LCS(X_m,Y_n,Z_{k - 1})</tex> | ||
+ | # Если <tex>z_k \neq x_m \neq y_n</tex>, то из <tex>y_n \neq v_h</tex> следует, что <tex>V</tex> — <tex>LCS(X_m,Y_{n - 1},Z_k)</tex> | ||
+ | # Если <tex>z_k \neq x_m \neq y_n</tex>, то из <tex>x_m \neq v_h</tex> следует, что <tex>V</tex> — <tex>LCS(X_{m - 1},Y_n,Z_k)</tex> | ||
+ | }} | ||
+ | ===Решение=== | ||
+ | Обозначим как <tex> lcs[i][j][l] </tex> <tex>LCS</tex> префиксов данных последовательностей, заканчивающихся в элементах с номерами <tex> i </tex>, <tex> j </tex> и <tex> l </tex> соответственно. Получается следующее рекуррентное соотношение: | ||
+ | |||
+ | <tex> | ||
+ | lcs[i][j][l] = | ||
+ | \begin{cases} | ||
+ | 0, & i = 0\text{ or }j = 0\text{ or }l = 0 \\ | ||
+ | lcs[i - 1][j - 1][l - 1] + 1, & x[i] = y[j] = z[l] \\ | ||
+ | max(lcs[i][j - 1][l], lcs[i - 1][j][l], lcs[i][j][l - 1]), & x[i] \neq y[j] \neq z[l] | ||
+ | \end{cases} | ||
+ | </tex> | ||
+ | |||
+ | Очевидно, что сложность алгоритма составит <tex> O(mnk) </tex>, где <tex> m </tex>, <tex> n </tex> и <tex> k </tex> — длины последовательностей. | ||
+ | |||
+ | Аналогичным образом задача решается для k строк. Заполняется k-мерная динамика. | ||
== См. также == | == См. также == | ||
*[[Задача о наибольшей возрастающей подпоследовательности]] | *[[Задача о наибольшей возрастающей подпоследовательности]] |
Версия 21:56, 14 января 2015
Определение: |
Последовательность | является подпоследовательностью (англ. subsequence) последовательности , если существует строго возрастающая последовательность индексов таких, что для всех выполняется соотношение .
Другими словами, подпоследовательность данной последовательности — это последовательность, из которой удалили ноль или больше элементов. Например,
является подпоследовательностью последовательности , а соответствующая последовательность индексов имеет вид .Определение: |
Последовательность | является общей подпоследовательностью (англ. common subsequence) последовательностей и , если является подпоследовательностью как , так и .
Задача: |
Пусть имеются последовательности | и . Необходимо найти
Содержание
Наивное решение
Переберем все различные подпоследовательности обеих строк и сравним их. Тогда искомая
гарантированно найдётся, однако время работы алгоритма будет экспоненциально зависеть от длины исходных последовательностей.Динамическое программирование
Для решения данной задачи используем Принцип оптимальности на префиксе.
Доказательство оптимальности
Теорема: |
Пусть имеются последовательности и , а — их .
|
Доказательство: |
|
Решение
Обозначим как
префиксов данных последовательностей, заканчивающихся в элементах с номерами и соответственно. Получается следующее рекуррентное соотношение:
Очевидно, что сложность алгоритма составит
, где и — длины последовательностей.Построение подпоследовательности
Для каждой пары элементов помимо длины
соответствующих префиксов хранятся и номера последних элементов, участвующих в этой .Таким образом, посчитав ответ, можно восстановить всю наибольшую общую подпоследовательность.Псевдокод
, — данные последовательности; — для префикса длины последовательности и префикса длины последовательности ; — пара индексов элемента таблицы, соответствующего оптимальному решению вспомогательной задачи, выбранной при вычислении .
// подсчёт таблиц int LCS(x: int, y : int): m = length(x) n = length(y) for i = 1 to m lcs[i][0] = 0 for j = 0 to n lcs[0][j] = 0 for i = 1 to m for j = 1 to n if x[i] == y[j] lcs[i][j] = lcs[i - 1][j - 1] + 1 prev[i][j] = pair(i - 1, j - 1) else if lcs[i - 1][j] >= lcs[i][j - 1] lcs[i][j] = lcs[i - 1][j] prev[i][j] = pair(i - 1, j) else lcs[i][j] = lcs[i][j - 1] prev[i][j] = pair(i, j - 1) // вывод LCS, вызывается как printLCS(m, n) int printLCS(i: int, j: int): if i == 0 or j == 0 // пришли к началу LCS return if prev[i][j] == pair(i - 1, j - 1) // если пришли в lcs[i][j] из lcs[i - 1][j - 1], то x[i] == y[j], надо вывести этот элемент printLCS(i - 1, j - 1) print x[i] else if prev[i][j] == pair(i - 1, j) printLCS(i - 1, j) else printLCS(i, j - 1)
Оптимизация для вычисления только длины
Заметим, что для вычисления
нужны только -ая и -ая строчки матрицы . Тогда можно использовать лишь элементов таблицы:int LCS2(x: int, y: int): if length(x) < length(y) // в таблице будет length(y) столбцов, и если length(x) меньше, выгоднее поменять местами x и y swap(x, y) m = length(x) n = length(y) for j = 0 to n lcs[0][j] = 0 lcs[1][j] = 0 for i = 1 to m lcs[1][0] = 0 for j = 1 to n lcs[0][j] = lcs[1][j] // элемент, который был в a[1][j], теперь в предыдущей строчке if x[i] == y[j] lcs[1][j] = lcs[0][j - 1] + 1 else if lcs[0][j] >= lcs[1][j - 1] lcs[1][j] = lcs[0][j] else lcs[1][j] = lcs[1][j - 1] // ответ — lcs[1][n]
Также можно заметить, что от
-ой строчки нужны только элементы с -го столбца. В этом случае можно использовать лишь элементов таблицы:int LCS3(x: int, y: int): if length(x) < length(y) // в таблице будет length(y) столбцов, и если length(x) меньше, выгоднее поменять местами x и y swap(x, y) m = length(x) n = length(y) for j = 0 to n lcs[j] = 0 d = 0 // d — дополнительная переменная, в ней хранится lcs[i - 1][j - 1] // в lcs[j], lcs[j + 1], …, lcs[n] хранятся lcs[i - 1][j], lcs[i - 1][j + 1], …, lcs[i - 1][n] // в lcs[0], lcs[1], …, lcs[j - 1] хранятся lcs[i][0], lcs[i][1], …, lcs[i][j - 1] for i = 1 to m for j = 1 to n tmp = lcs[j] if x[i] == y[i] lcs[j] = d + 1 else if lcs[j] >= lcs[j - 1] lcs[j] = lcs[j] // в lcs[j] и так хранится lcs[i - 1][j] else lcs[j] = lcs[j - 1] d = tmp // ответ — lcs[n]
Длина кратчайшей общей суперпоследовательности
Для двух подпоследовательностей [1]
и длина кратчайшая общей суперпоследовательности равнаРешение для случая k строк
Найдем решение для 3 строк.
Задача: |
Пусть имеются последовательности | , и . Необходимо найти
Нельзя подсчитать
, а потом . Это легко доказывается контрпримером. Даны три строки:
Подсчитаем
Это неверно, так какТеорема: |
Пусть имеются последовательности , и , а — их .
|
Решение
Обозначим как
префиксов данных последовательностей, заканчивающихся в элементах с номерами , и соответственно. Получается следующее рекуррентное соотношение:
Очевидно, что сложность алгоритма составит
, где , и — длины последовательностей.Аналогичным образом задача решается для k строк. Заполняется k-мерная динамика.
См. также
- Задача о наибольшей возрастающей подпоследовательности
- Наибольшая общая возрастающая подпоследовательность
- Задача о наибольшей общей палиндромной подпоследовательности
Примечания
Список литературы
- Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 2-е изд. — М.: «Вильямс», 2007. — с. 459. — ISBN 5-8489-0857-4