密码脱落
X星球的考古学家发现了一批古代留下来的密码。
这些密码是由A、B、C、D 四种植物的种子串成的序列。
仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。
由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是:
给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。
输入格式
共一行,包含一个由大写字母ABCD构成的字符串,表示现在看到的密码串。
输出格式
输出一个整数,表示至少脱落了多少个种子。
数据范围
输入字符串长度不超过1000
输入样例1:
ABCBA
输出样例1:
0
输入样例2:
ABDCDCBABC
输出样例2:
3
思路分析:
res = 添几个字符变回文串 <-等价于-> 删几个字符变为回文串 <-等价于-> 总长度 - 最长回文子序列的长度
状态表示:
f[l][r] 表示所有s[l ~ r] 之间的回文子序列的集合的长度最大值
划分:
1. l和r都不在 f[l + 1][r - 1]
2. l在r不在 f[l][r - 1]
3. l不在r在 f[l + 1][r]
4. l和r都在 f[l + 1][r - 1] + 2
状态转移方程:
f[l][r] = max(f[l][r - 1], f[l + 1][r])
f[l][r] = max(f[l][r], f[l + 1][r - 1] + 2)
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
const int N = 1010;
char s[N];
int f[N][N];
int main()
{
scanf("%s", s);
int n = strlen(s);
for (int len = 1; len <= n; len ++)
for (int l = 0; l + len - 1 < n; l ++)
{
int r = l + len - 1;
if (len == 1) f[l][r] = 1;
else
{
f[l][r] = max(f[l][r - 1], f[l + 1][r]);
if (s[l] == s[r]) f[l][r] = max(f[l][r], f[l + 1][r - 1] + 2);
}
}
cout << n - f[0][n - 1] << endl;
return 0;
}