НСП - 2#4260

НСП - 2 (Розбір)

В задачі слід знайти найбільшу спільну підпослідовність (НОП) двох рядків і вивести її.

Побудуємо масив , де dp[i][j] дорівнює довжині НОП рядків x_{[1 \ldots i]} і y_{[1 \ldots j]}. Значення буде дорівнювати довжині НОП початкових рядків (|x| = n, |y| = m).

Після обчислення масиву відновимо НОП, здійснивши зворотний прохід по матриці від комірки до . Для поточної позиції виконуємо наступні кроки:

Результуючий рядок буде містити найбільшу спільну підпослідовність рядків і .

Приклад

Розглянемо процес знаходження найбільшої спільної підпослідовності (НОП) для двох рядків, наведених у прикладі.

Пошук спільної підпослідовності починається з позиції (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;