Назад

Методы программирования

Задание 9. Задание на динамическое программирование

Общая информация

В данном задании необходимо реализовать алгоритм поиска наибольшей общей подпоследовательности, иногда называемый алгоритмом Ахо. Задание является обязательным для выполнения.

Теория

Динамическим программированием называется метод решения задач путем сведения их к аналогичным задачам меньшего размера, причем результаты решения этих задач сохраняются и используются для решения исходной задачи.

Многие рекурсивные алгоритмы с возвратом можно переписать динамически. Обычно такая реализация требует больше памяти, чем рекурсия (для хранения промежуточных значений), но работает заметно быстрее.

Рассмотрим следующую задачу. Даны две строки (последовательности символов) длиной M и N соответственно. Необходимо найти наибольшую общую подстроку этих двух строк. Например, для строк "abcd" и "aacd" наибольшей подстрокой будет строка "acd".

Попробуем разбить задачу на аналогичные подзадачи меньшего размера. Пусть даны две строки s и t. Сравним последние символы этих строк. Если они совпадают, то решением, очевидно, будет набольшая подстрока для строк s без последнего символа и t без последнего символа, к которой добавили тот самый совпадающий последний символ. Например, если s = "abcd" и t = "aacd", то решением задачи будет общая подстрока строк "abc" и "aac" с добавленным к ней в конце символом d.

Если же последние символы не совпадают, то рассмотрим два варианта: отбросим последний символ сначала у одной строки, а затем у другой, и выберем наилучший из этих вариантов.

Ясно, что такой алгоритм легко реализуется рекурсивно. Однако, можно предложить более хорошее решение. Построим матрицу A[M][N], в которой элемент A[i][j] будет хранить длину наибольшей общей подстроки строки из первых i символов s и первых j символов t. Другими словами, A[i][j] — решение аналогичной задачи для двух строк длиной i и j соответственно. Заполнить таблицу такими значениями легко, двигаясь слева направо и сверху вниз: для каждой клетки (i, j) выполняем проверку:

  1. Если s[i] = t[j], в клетку (i, j) поставим увеличенное на единицу значение клетки (i – 1, j – 1).
  2. В противном случае значением клетки будет максимум из значения соседней клетки сверху и значения соседней клетки слева.

Для строк "abcd" и "aacd" таблица будет заполнена следующим образом:

0 abcd
a 1 1 1 1
a 1 1 1 1
c 1 1 2 2
d 1 1 2 3

По построению таблицы, в правом нижнем углу — длина наибольшей общей подстроки. Восстановить саму подстроку можно, «раскручивая» алгоритм в обратную сторону.

Формулировка задания

Во входном файле input.txt даны две строки. Выдать в выходной файл output.txt их наибольшую общую подстроку.