题面
主要大衣大意:
给定一个字符串,求至少加入多少个字符才能使字符串变成回文字符串
下面就是我一本正经的胡说八道题解
思路:
很显然,这应该是一道典型的最长公共子序列的题目
因此,主要思想就是DP
方程式也挺好推的
于是我们就来讲一下为什么这题能用最长公共子序列(LCS)求解
证明:
求的是什么?
想要使这个字符串加入最少的字符变成一个回文串,那么肯定就是要是字符串中不能回文的部分回文
说起来比较难理解,比如:Ab3bd
最少添的字符就是A
对应的一个A
,最后d
对应的一个d
我们可以发现,最少要添的字符就是不能匹配的字符数=原字符串长度len-最长回文串的长度
这就变成了求最长回文串的题目
怎么求?
又经验的人肯定就会用最长公共子序列去解,但是一些人可能要问为什么,那么我们这里就来证明一下
由于回文串是回文的(废话),也就是说,把原来的字符串反转一遍,最长回文串的长度还是不变的
于是我们就变成了求两串的公共子序列的长度——其实思想就是回文串正着和反着的效果是一样的,也就是抓住这个特性,去求公共系序列的长度
转移方程(最好自己去推一下):
if(a[i]==b[j])//目标状态是f[len][len]
f[i][j]=f[i-1][j-1]+1;//表示i,j两位置相等,那么就由i-1,j-1的状态(最优解)+1得到
else
f[i][j]=max(f[i-1][j],f[i][j-1]);//否则去掉i或j,转移最优解
Code:
#include<bits/stdc++.h>
#define N 1010
using namespace std;
int len;
char a[N],b[N];
int f[N][N];
int main()
{
int i,j;
scanf("%s",a+1);
len=strlen(a+1);
for(i=1;i<=len;i++)
b[i]=a[len-i+1];//反转
for(i=1;i<=len;i++)
for(j=1;j<=len;j++)
if(a[i]==b[j])
f[i][j]=f[i-1][j-1]+1;
else
f[i][j]=max(f[i-1][j],f[i][j-1]);
printf("%d",len-f[len][len]);//长度减去最长回文串长度
return 0;
}
拓展知识:
最长上升子序列(LIS)