В задачі слід знайти найбільшу спільну підпослідовність (НОП) двох рядків і вивести її.
Побудуємо масив , де dp[i][j] дорівнює довжині НОП рядків x_{[1 \ldots i]} і y_{[1 \ldots j]}. Значення буде дорівнювати довжині НОП початкових рядків (|x| = n, |y| = m).
Після обчислення масиву відновимо НОП, здійснивши зворотний прохід по матриці від комірки до . Для поточної позиції виконуємо наступні кроки:
якщо символи x_i і y_j збігаються, цей символ має бути включений в НОП. Додаємо його в результуючий рядок і переходимо до комірки (i - 1, j - 1), тобто продовжуємо будувати НОП для рядків x_{[1 \ldots i - 1]} і y_{[1 \ldots j - 1]}.
якщо символи x_i і y_j різні, то переходимо до комірки (i, j - 1) або (i - 1, j), вибираючи ту, де значення більше. Якщо значення в комірках dp[i - 1][j] і dp[i][j - 1] рівні, перехід можливий в будь-яку з них.
Результуючий рядок буде містити найбільшу спільну підпослідовність рядків і .
Приклад
Розглянемо процес знаходження найбільшої спільної підпослідовності (НОП) для двох рядків, наведених у прикладі.
Пошук спільної підпослідовності починається з позиції (i, j) = (6, 7).
y[6] \ne x[7]: переходимо в будь-яку сусідню комірку з максимальним значенням, наприклад, до .
y[5] \ne x[7]: рухаємося до .
y[5] = x[6] = '': здійснюємо перехід по діагоналі і включаємо букву '' у НОП.
Реалізація алгоритму
Оголосимо вхідні рядки і . Для знаходження їх НОП використовуємо масив .
#define MAX 1001
int dp[MAX][MAX];
string x, y, res;Читаємо вхідні рядки і додаємо до них пробіл спереду, щоб індексація починалася з .
cin >> x; n = x.length(); x = " " + x;
cin >> y; m = y.length(); y = " " + y;Знаходимо НОП.
for (i = 1; i <= n; i++)
for (j = 1; j <= m; j++)
if (x[i] == y[j])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);У рядку будуємо НОП.
i = n; j = m;
while (i >= 1 && j >= 1)
if (x[i] == y[j])
{
res = res + x[i];
i--; j--;
}
else
{
if (dp[i - 1][j] > dp[i][j - 1])
i--;
else
j--;
}Звертаємо і виводимо результуючий рядок.
reverse(res.begin(), res.end());
cout << res << endl;