Задача о наименьшей суперпоследовательности
Версия от 17:27, 27 декабря 2017; Motyaspr (обсуждение | вклад)
Определение: |
Последовательность | является суперпоследовательностью (англ. supersequence) последовательности , если — подпоследовательность , то есть существует строго возрастающая последовательность индексов таких, что для всех выполняется соотношение , при этом .
Определение: |
Последовательность | является общей суперпоследовательностью (англ. common supersequence) последовательностей и , если является суперпоследовательностью как для , так для и .
Задача: |
Пусть имеются последовательности | и . Необходимо найти , где — длина наименьшей общей суперпоследовательности последовательностей и
Наивное решение
Пусть даны две последовательности длин
и соответственно. Заметим, что если приписать к одной из данных последовательностей другую, то полученная последовательность будет их суперпоследовательностью с длиной . Запомним все элементы обеих последовательностей и из них построим все возможные последовательности. Тогда искомая гарантированно найдётся, однако время работы алгоритма будет экспоненциально зависеть от длин исходных последовательностей.Динамическое программирование
Решение
Обозначим за
наименьшую общую суперпоследовательность для префиксов данных последовательностей и , заканчивающихся в элементах с номерами и соответственно. Наименьшая общая суперпоследовательность и должна содержать каждый символ обеих последовательностей, поэтому если , то это просто последовательность . Аналогичен случай, когда . Если и , то возможны два случая. Если , то должна включать оба этих элемента. Значит нужно выбрать минимальный из ответов для префиксов, включающих один элемент и не включающих второй. Если же , то для последовательностей и должна заканчиваться этим элементом, так как он общий для них. Получается следующее рекуррентное соотношение:
Cложность алгоритма составит
, где и — длины последовательностей.Восстановление ответа
Для восстановления ответа заведем массив
, где будет равняться:
По этим данным можно узнать, какой символ был добавлен в наименьшую общую суперпоследовательность.
Псевдокод
— данные последовательности; — для префикса длины последовательности и префикса длины последовательности ; — массив для восстановления ответа.
fun SCS(x: int, y: int): // аналог void n = x.size m = y.size for i = 0 to n scs[i][0] = i for j = 0 to m scs[0][j] = j for i = 1 to n for j = 1 to m if x[i] == y[j] scs[i][j] = 1 + scs[i - 1][j - 1] prev[i][j] = 1 else if scs[i - 1][j] > scs[i][j - 1] scs[i][j] = 1 + scs[i][j - 1] prev[i][j] = 2 else scs[i][j] = 1 + scs[i - 1][j] prev[i][j] = 3 fun printSCS(n: int, m: int): // вывод SCS i = n j = m ans = [] // массив ответа while i > 0 and j > 0 if prev[i][j] == 1 ans.append(x[i]) i -= 1 j -= 1 else if prev[i][j] == 2 ans.append(y[j]) j -= 1 else ans.append(x[i]) i -= 1 while i > 0 // добавляем оставшиеся символы первой последовательности ans.append(x[i]) i -= 1 while j > 0 ans.append(y[j]) // добавляем оставшиеся символы второй последовательности j -= 1 reverse(ans) // разворачиваем последовательность, так как шли с конца return ans
Связь с наибольшей общей подпоследовательностью
Теорема: |
наибольшей общей подпоследовательности, — длина наименьшей общей суперпоследовательности, и — длины последовательностей и соответственно. , где — длина |
Доказательство: |
Пусть Поэтому: , . Обозначим за их и будем ее строить. Так как являетcя суперпоследовательностью , то можно представить так: Мы должны на место некоторых пропусков поставить элементы , так чтобы суммарная длина была минимальна, и являлась суперпоследовательностью . Рассмотрим любую общую подпоследовательность и .Заметим, что она уже находятся в , а значит все её элементы не нужно добавлять. Поэтому мы добавим не меньше, чем . Длину нужно минимизировать, значит имеет место равенство: . |