Задача о наименьшей суперпоследовательности — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 32: Строка 32:
 
</tex>
 
</tex>
  
Очевидно, что сложность алгоритма составит <tex> O(mn) </tex>, где <tex> m </tex> и <tex> n </tex> — длины последовательностей.
+
Cложность алгоритма составит <tex> O(mn) </tex>, где <tex> m </tex> и <tex> n </tex> — длины последовательностей.
  
 
===Восстановление ответа===
 
===Восстановление ответа===
В <tex> scs[i][j] </tex> помимо длины последовательности хранится и символ, добавленный последним. Таким образом, зная длину SCS, можно восстановить и саму последовательность.
+
Для восстановления ответа заведем массив <tex> prev[0 \dots n][0\dots m] </tex>, где <tex>prev[i][j]</tex> будет означать индексы в массиве <tex>scs</tex>, при которых достигалось наименьшее значение <tex>sc[i][j]</tex>.
  
 
===Псевдокод===
 
===Псевдокод===
Строка 60: Строка 60:
 
             prev[i][j] = pair(i, j - 1)
 
             prev[i][j] = pair(i, j - 1)
 
    
 
    
  '''fun''' printLCS(m: '''int''', n: '''int'''): ''<font color="green">// вывод SCS</font>''
+
  '''fun''' printLCS(n: '''int''', m: '''int'''): ''<font color="green">// вывод SCS</font>''
     i = m
+
     i = n
     j = n
+
     j = m
 
     ans = [] ''<font color="green">// массив ответа </font>''
 
     ans = [] ''<font color="green">// массив ответа </font>''
 
     '''while''' i > 0 '''and''' j > 0
 
     '''while''' i > 0 '''and''' j > 0

Версия 22:43, 23 декабря 2017

Определение:
Последовательность [math] Z = \left \langle z_1, z_2, \dots, z_k \right \rangle [/math] является суперпоследовательностью (англ. supersequence) последовательности [math] X = \left \langle x_1, x_2, \dots, x_m \right \rangle [/math], если существует строго возрастающая последовательность [math] \left \langle i_1, i_2, \dots, i_m \right \rangle [/math] индексов [math] Z [/math] таких, что для всех [math] j = 1, 2, \dots, m [/math] выполняется соотношение [math] z_{i_j} = x_j [/math].


Определение:
Последовательность [math] Z [/math] является общей суперпоследовательностью (англ. common supersequence) последовательностей [math] X [/math] и [math] Y [/math], если [math] Z [/math] является суперпоследовательностью как для [math] X [/math], так для и [math] Y [/math].


Задача:
Пусть имеются последовательности [math] X = \left \langle x_1, x_2, \dots, x_m \right \rangle [/math] и [math] Y = \left \langle y_1, y_2, \dots, y_n \right \rangle [/math]. Необходимо найти [math]SCS(X,Y)[/math]


Наивное решение

Пусть даны две последовательности длины [math]n[/math] и [math]m[/math] соответственно. Заметим, что если приписать к одной из данных последовательностей другую, то полученная последовательность будет их суперпоследовательностью с длиной [math] n + m [/math]. Запомним все элементы обеих последовательностей и из них построим все возможные последовательности. Тогда искомая [math]SCS[/math] гарантированно найдётся, однако время работы алгоритма будет экспоненциально зависеть от длины исходных последовательностей.


Динамическое программирование

Решение

Обозначим за [math] scs[i][j] SCS [/math] префиксов данных последовательностей [math] x[1 \dots n] [/math] и [math] y[1 \dots m] [/math], заканчивающихся в элементах с номерами [math] i [/math] и [math] j [/math] соответственно. Наименьшая общая суперпоследовательность [math] x[1 \dots i] [/math] и [math] y[1 \dots j] [/math] должна содержать каждый символ обеих последовательностей, поэтому если [math] j = 0 [/math], то [math] SCS [/math] это просто последовательность [math] x[1 \dots i] [/math]. Аналогичен случай, когда [math] i = 0 [/math]. Если [math] i \gt 0 [/math] и [math] j \gt 0 [/math], то возможны два случая. Если [math] x[i] \neq y[j] [/math], то SCS должна включать оба этих элемента. Значит нужно выбрать минимальный из ответов для префиксов, включающих один элемент и не включающих второй. Если же [math] x[i] = y[j] [/math], то [math]SCS[/math] для последовательностей [math] x[1 \dots i] [/math] и [math] y[1 \dots j] [/math] должна заканчиваться этим элементом, так как он общий для них. Получается следующее рекуррентное соотношение:

[math] scs[i][j] = \begin{cases} i, & j = 0 \\ j, & i = 0 \\ 1 + scs[i - 1][j - 1], & x[i] = y[j] \\ 1 + min(scs[i][j - 1],\ scs[i - 1][j]), & x[i] \neq y[j] \end{cases} [/math]

Cложность алгоритма составит [math] O(mn) [/math], где [math] m [/math] и [math] n [/math] — длины последовательностей.

Восстановление ответа

Для восстановления ответа заведем массив [math] prev[0 \dots n][0\dots m] [/math], где [math]prev[i][j][/math] будет означать индексы в массиве [math]scs[/math], при которых достигалось наименьшее значение [math]sc[i][j][/math].

Псевдокод

x, y — данные последовательности; [math]scs[i][j] [/math] — SCS для префикса длины i последовательности x и префикса длины j последовательности y; prev[i][j] — пара индексов элемента таблицы, которые предшествовали [math]scs[i][j][/math].

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)
 
fun printLCS(n: int, m: int): // вывод SCS
   i = n
   j = m
   ans = [] // массив ответа 
   while i > 0 and j > 0
     if prev[i][j] == pair(i - 1, j - 1)
       ans.append(x[i])
       i -= 1
       j -= 1
     else
       if prev[i][j] == pair(i - 1, j)
         ans.append(x[i])
         i -= 1
       else
         ans.append(y[j])
         j -= 1
   while i > 0 // добавляем оставшиеся символы первой последовательности 
     ans.append(x[i])
     i -= 1
   while j > 0
     ans.append(y[j]) // добавляем оставшиеся символы второй последовательности 
     j -= 1
   reverse(ans) // разворачиваем последовательность, так как шли с конца 
   return ans

Связь с наибольшей общей подпоследовательностью

Теорема:
[math]|LCS(X, Y)| + |SCS(X, Y)| = n + m[/math], где [math]|LCS(X, Y)|[/math] - длина наибольшей общей подпоследовательности, [math]|SCS(X, Y)|[/math] - длина наименьшей общей суперпоследовательности, [math]n[/math] и [math]m[/math] - длины последовательностей [math] X [/math] и [math] Y [/math] соответсвенно.
Доказательство:
[math]\triangleright[/math]

Пусть [math] X = \left \langle x_1, x_2, \dots, x_n \right \rangle [/math], [math] Y = \left \langle y_1, y_2, \dots, x_m \right \rangle [/math]. Обозначим за [math] S [/math] их SCS и будем ее строить. Так как [math]X[/math] являетcя подпоследовательностью [math] S [/math], то можно представить [math]S[/math] так: [math] S = \dots x_1 \dots x_2 \dots x_i \dots x_n \dots [/math] Мы должны поставить на место некоторых пропусков поставить элементы [math]Y[/math], так чтобы суммарная длина [math] S [/math] была минимальна, и [math] Y [/math] был подпоследовательностью [math]S[/math]. Заметим, что если найдется подпоследовательность [math]Y[/math] такая, что является подпоследовательностью [math] X [/math], то все элементы этой подпоследовательности уже находятся в [math]S[/math], а значит их не нужно вставлять. Поэтому мы добавим не меньше чем [math] m - |LCS(X, Y)| элементов [/math]. Длину [math] SCS(X, Y) [/math] нужно минимизировать, значит имеет место равенство: [math]|SCS(X,Y)| = n + (m - |LCS(X, Y)|)[/math].

Поэтому: [math]|LCS(X, Y)| + |SCS(X, Y)| = n + m[/math]
[math]\triangleleft[/math]

См. также

Источники информации