Из данной строки
удалите наименьшее количество символов так, чтобы получился палиндром (строка,
одинаково читающаяся как справа налево, так и слева направо).
Вход. Непустая строка длиной не более 100 символов. Строка
состоит только из заглавных латинских букв.
Выход. Выведите строку -
палиндром максимальной длины, которую можно получить из исходной строки путем
удаления некоторых букв. Если существует несколько таких палиндромов, выведите
любой из них.
Пример
входа |
Пример
выхода |
WQWQEWAEQ |
QWEWQ |
динамическое
программирование
наибольшая
общая подпоследовательность
Рассмотрим
исходную строку и ее реверс. Максимальный подпалиндром – это наибольшая общая
подпоследовательность строки и ее реверса. Такой алгоритм работает за O(n2).
Пример
Найдем
наибольшую общую подпоследовательность входной строки и ее реверса.
Объявим рабочие
массивы. Входную строку содержим в x, ее реверс в y. Максимальный
подпалиндром строим в res. Для динамики используем двумерный массив m.
#define MAX 110
string x, y, res;
int m[MAX][MAX];
Читаем входную
строку. Находим ее реверс в y. В начало строк x и y поставим пробел.
cin >> x; y = x;
reverse(y.begin(), y.end());
x = ' ' + x; y = ' ' + y;
len = x.size();
Запускаем алгоритм вычисления наибольшей общей
подпоследовательности.
memset(m,0,sizeof(m));
for(i = 1; i < len; i++)
for(j = 1; j < len; j++)
if (x[i] ==
y[j]) m[i][j] = 1 + m[i-1][j-1];
else m[i][j]
= max(m[i-1][j],m[i][j-1]);
По массиву m восстанавливаем НВП.
i = j = len - 1;
res = "";
while(m[i][j] > 0)
{
if (x[i] ==
y[j])
{
res += x[i];
i--; j--;
}
else if (m[i-1][j] > m[i][j-1]) i--; else j--;
}
Выводим искомый максимальный подпалиндром.
cout << res << endl;
Объявим рабочий
массив dp.
#define MAX 101
int dp[MAX][MAX];
Функция f вычисляет длину палиндрома наибольшей длины, который можно получить из строки s[i .. j] и запоминает это
значениек в dp[i][j].
int f(int i, int j)
{
if (i > j) return 0;
if (i == j) return 1;
if (dp[i][j] != -1) return dp[i][j];
if (s[i] == s[j])
return dp[i][j] = f(i + 1, j - 1) + 2;
else
return dp[i][j] = max(f(i + 1, j), f(i, j - 1));
}
Функция print выводит палиндром наибольшей длины, который можно получить из строки s[i .. j]. Используются
ранее вычиленные значения массива dp.
void print(int i, int j)
{
if (i > j) return;
if (i == j)
{
cout << s[i];
return;
}
if (s[i] == s[j])
{
cout << s[i];
print(i + 1, j - 1);
cout << s[j];
}
else
{
if (dp[i + 1][j] > dp[i][j - 1])
print(i + 1, j);
else
print(i, j - 1);
}
}
Основная часть программы. Читаем входную строку s.
cin >> s;
memset(dp,
-1, sizeof(dp));
Вычисляем и выводим ответ.
f(0,
s.size());
print(0,
s.size());
cout << endl;