Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 60920 | Accepted: 21245 |
Description
As an example, by inserting 2 characters, the string "Ab3bd" can be transformed into a palindrome ("dAb3bAd" or "Adb3bdA"). However, inserting fewer than 2 characters does not produce a palindrome.
Input
Output
Sample Input
5 Ab3bd
Sample Output
2
题意:
给定一个长度为N的字符串。问你最少要插入多少个字符才能使它变成回文串。
分析:
一开始没看出来是LCS。假设原串和其倒过来的字符串的最长公共子序列长度为m,原串长度为n,则意味着原串中有m个字符是正着反着读顺序都一样的,那么只需要在合适的位置插入n-m个相应的字符,就可以使得整个串成为回文串。
先求得原串的逆串,通过DP求两者最长公共子序列的长度。自上而下,从左到右填充dp矩阵。
转译方程为:
if(a[i]==b[j]) dp[k][j]=dp[!k][j-1]+1;//当前位相同,截止当前位的LCS长度等于两个串都不考虑当前位时的LCS长度加一
else dp[k][j]=max(dp[!k][j],dp[k][j-1]);//否则,将其前面和上面方格中的较大值传递过来
由于题目给定空间有限,本题引入滚动数组(也可以用short代替int),并通过!运算符实现换行。和填充正方形矩阵的过程一样,填这个之前其前面的和上面的都已经填好了。
借一幅图加深理解:
(图片地址:http://blog.youkuaiyun.com/jianfpeng241241/article/details/51926420)
代码:
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
using namespace std;
char a[5009],b[5009];
int dp[2][5009];
int main(){
int n;
while(~scanf("%d",&n)){
scanf("%s",a);
for(int i=0;i<n;i++){
b[n-i-1]=a[i];
}
memset(dp,0,sizeof(dp));
int k=0;
for(int i=0;i<n;i++,k=!k){
for(int j=0;j<n;j++){
if(a[i]==b[j]) dp[k][j]=dp[!k][j-1]+1;
else dp[k][j]=max(dp[!k][j],dp[k][j-1]);
}
}
int ans=max(dp[0][n-1],dp[1][n-1]);
printf("%d\n",n-ans);
}
return 0;
}