X星球的考古学家发现了一批古代留下来的密码。
这些密码是由A、B、C、D 四种植物的种子串成的序列。
仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是:
给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。
输入格式
共一行,包含一个由大写字母ABCD构成的字符串,表示现在看到的密码串。
输出格式
输出一个整数,表示至少脱落了多少个种子。
数据范围
输入字符串长度不超过1000
输入样例1:
ABCBA
输出样例1:
0
输入样例2:
ABDCDCBABC
输出样例2:
3
思路:
如果一个字符串是回文的, 必然有最后一个字符与第一个字符相同,于是我们以最后一个字符与第一个字符是否相同为划分集合的依据。
f[i][j] 表示字符串 s[i ~ j] 转化为回文串所需的最小步数
s[i] != s[j] 此时需要 在 s[i - 1] 处添加字符 c = s[j] 或者 在 s[j + 1] 处添加字符 c = s[i]
添加字符后两边字符相同, 这时候可以同时删去 s[i - 1] 和 s[j] 或者 s[j + 1] 和 s[i]
于是有 f[i][j] = min(f[i][j - 1], f[i + 1][j]) + 1
s[i] == s[j] 无需添加, 直接删去两个相同字符即可
f[i][j] = f[i + 1][j - 1]
代码:
#include <iostream>
using namespace std;
const int N = 1e3 + 10;
string str;
int dp[N][N];
int main() {
cin >> str;
int len = str.length();
for (int i = 1; i <= len; i ++ ) {
for (int j = 0; j < len - i + 1; j ++ ) {
int r = j + i - 1;
if (i == 1) dp[j][r] = 1;
else {
dp[j][r] = max(dp[j + 1][r], dp[j][r - 1]);
if (str[j] == str[r])
dp[j][r] = max(dp[j][r], dp[j + 1][r - 1] + 2);
}
}
}
cout << len - dp[0][len - 1];
}