题目大意:给你一个字符串(区分大小写),要求你添加最少的字符使其变成回文串,问最少添加几个字符。
思路:此题的答案=原字符串长度-原字符串与前后颠倒后的字符串的最长公共子串长度(LCS)。
求LCS用DP。
此题字符串最长能达5000,数组需要开5000*5000*int,会“炸”(MLE)。解决办法:①用short;②用滚动数组。
下面是两者的对比(上面是方法①,下面是方法②):

由此可见,方法②完胜方法①(尤其是内存,相差49028K!)。(不会滚动数组的使用方法①也是个选择)
C++ Code:
方法①:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char a[5005],b[5005];
int dp[2][5005];
int l;
int main(){
while(scanf("%d",&l)!=EOF){
memset(a,0,sizeof(a));
a[0]='^';
scanf("%s",a+1);
strcpy(b,a);
memset(dp,0,sizeof(dp));
reverse(b+1,b+l+1);
int Max=0;
for(int i=1;i<=l;i++)
for(int j=1;j<=l;j++){
if(a[i]==b[j])dp[i%2][j]=dp[(i-1)%2][j-1]+1;
else
dp[i%2][j]=max(dp[i%2][j-1],dp[(i-1)%2][j]);
if(Max<dp[i%2][j])Max=dp[i%2][j];
}
printf("%d
",l-Max);
}
return 0;
}
方法②:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char a[5005],b[5005];
short dp[5005][5005];
int l;
int main(){
while(scanf("%d",&l)!=EOF){
memset(a,0,sizeof(a));
a[0]='^';
scanf("%s",a+1);
strcpy(b,a);
memset(dp,0,sizeof(dp));
reverse(b+1,b+l+1);
for(int i=1;i<=l;i++)
for(int j=1;j<=l;j++){
if(a[i]==b[j])dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
}
printf("%d
",l-dp[l][l]);
}
return 0;
}