Задача о наименьшей суперпоследовательности — различия между версиями
Motyaspr (обсуждение | вклад) |
Motyaspr (обсуждение | вклад) |
||
Строка 38: | Строка 38: | ||
===Псевдокод=== | ===Псевдокод=== | ||
− | x, y — данные последовательности; scs[i][j] — SCS для префикса длины i последовательности x и префикса длины j последовательности y; prev[i][j] — пара индексов элемента таблицы, | + | x, y — данные последовательности; <tex>scs[i][j] </tex> — SCS для префикса длины i последовательности x и префикса длины j последовательности y; prev[i][j] — пара индексов элемента таблицы, которые предшествовали <tex>scs[i][j]</tex>. |
+ | |||
+ | '''fun''' SCS(x: '''int''', y: '''int'''): ''<font color="green">// аналог void </font>'' | ||
+ | m = x.size | ||
+ | n = y.size | ||
+ | '''for''' i = 1 '''to''' m | ||
+ | scs[i][0] = i | ||
+ | '''for''' j = 0 '''to''' n | ||
+ | scs[0][j] = j | ||
+ | '''for''' i = 1 '''to''' m | ||
+ | '''for''' j = 1 '''to''' n | ||
+ | '''if''' x[i] == y[j] | ||
+ | scs[i][j] = 1 + scs[i - 1][j - 1] | ||
+ | prev[i][j] = pair(i - 1, j - 1) | ||
+ | '''else''' | ||
+ | '''if''' scs[i - 1][j] <= lcs[i][j - 1] | ||
+ | scs[i][j] = 1 + scs[i - 1][j] | ||
+ | prev[i][j] = pair(i - 1, j) | ||
+ | '''else''' | ||
+ | scs[i][j] = 1 + scs[i][j - 1] | ||
+ | prev[i][j] = pair(i, j - 1) | ||
+ | |||
+ | '''int''' printLCS(m: '''int''', n: '''int'''): ''<font color="green">// вывод SCS, вызывается как printLCS(m, n)</font>'' | ||
+ | '''if''' i == 0 '''or''' j == 0 ''<font color="green">// пришли к началу LCS</font>'' | ||
+ | '''return''' | ||
+ | '''if''' prev[i][j] == pair(i - 1, j - 1) ''<font color="green">// если пришли в lcs[i][j] из lcs[i - 1][j - 1], то x[i] == y[j], надо вывести этот элемент</font>'' | ||
+ | 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) |
Версия 19:23, 23 декабря 2017
Определение: |
Последовательность | является суперпоследовательностью (англ. supersequence) последовательности , если существует строго возрастающая последовательность индексов таких, что для всех выполняется соотношение .
Определение: |
Последовательность | является общей суперпоследовательностью (англ. common supersequence) последовательностей и , если и являются подпоследовательностями .
Задача: |
Пусть имеются последовательности | и . Необходимо найти
Содержание
Наивное решение
Заметим, что если приписать к одной из данной последовательность другую, то полученная последовательность будет их суперпоследовательностью с длиной
. Запомним все элементы обеих последовательностей и из них построим все возможные последовательности. Тогда искомая гарантированно найдётся, однако время работы алгоритма будет экспоненциально зависеть от длины исходных последовательностей.
Динамическое программирование
Решение
Обозначим за
SCS префиксов данных последовательностей и , заканчивающихся в элементах с номерами и соответственно. Наименьшая общая суперпоследовательность и должна содержать каждый символ обеих последовательностей, поэтому если , то это просто последовательность . Аналогичен случай, когда . Если и , то возможны два случая. Если , то SCS должна включать оба этих элемента. Значит нужно выбрать оптимальный из ответов для префиксов, включающих один элемент и не включающих второй, и выбрать из них минимальный. Если же , то SCS для последовательностей и должна заканчиваться этим элементом, так как он общий для них. Получается следующее рекуррентное соотношение:
Очевидно, что сложность алгоритма составит
, где и — длины последовательностей.Восстановление ответа
В
помимо длины последовательности хранятся и символ, добавленный последним. Таким образом, зная длину SCS, можно восстановить и саму последовательность.Псевдокод
x, y — данные последовательности;
— SCS для префикса длины i последовательности x и префикса длины j последовательности y; prev[i][j] — пара индексов элемента таблицы, которые предшествовали .fun SCS(x: int, y: int): // аналог void m = x.size n = y.size for i = 1 to m scs[i][0] = i for j = 0 to n scs[0][j] = j for i = 1 to m for j = 1 to n if x[i] == y[j] scs[i][j] = 1 + scs[i - 1][j - 1] prev[i][j] = pair(i - 1, j - 1) else if scs[i - 1][j] <= lcs[i][j - 1] scs[i][j] = 1 + scs[i - 1][j] prev[i][j] = pair(i - 1, j) else scs[i][j] = 1 + scs[i][j - 1] prev[i][j] = pair(i, j - 1) int printLCS(m: int, n: int): // вывод SCS, вызывается как printLCS(m, n) 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)