1346: 回文串

Time Limit: 1 Sec   Memory Limit: 128 MB

​Submit​​​][​​Status​​​][​​Web Board​​]

Description

对于一个给定的字符串你的任务是添加最少的字符使这个字符串变成一个回文串。回文串是指一个字符串从左往右和从右往左是一样的。例如“Ab3bd”可以变成"dAb3bAd"或者"Adb3bdA",所以“Ab3bd”的答案是2

Input

多组测试数据,每组测试数据包含一个字符串,字符串由数字,小写字母,大写字母组成(区分大小写)。字符串的长度小于5000。

Output

对于每组测试数据输出一个整数代表最少需要添加的字符个数。

Sample Input

Ab3bd

Aa

Sample Output

2

1

【分析】

(这道题....一开始直接dfs去补...虽然有剪枝但是一样TLE...

第一次修改是发现自己真蠢..这种东西不会写dp吗?! 然后dp写错了...n^3的dp...

又一次修改又一次发现自己真蠢...这种dp不会倒过来想吗?! 然后就AC了....)

以上都是废话....

这道题显然dfs超时了,所以用dp,但是不能去搜最小添加的字符个数,因为这样很难判断而且会需要n^3....

换个思路,在原来的字符串里可以组成的最大回文串的长度的长度是多少,剩下的字符我们去补一下就可以了~

所以,这道题其实就是给你一个字符串,求这个字符串里面的回文串最大有多长,然后总长度减去这个最长回文串的长度就可以了。

想到这一点之后就简单了,简单的dp,f[i][j]表示前i个字符和后j个字符能组成的最大回文串长度

先把原串倒过来,这样就有了两个串s1,s2,这样的话for循环就容易理解多了,就是s1前i个字符和s2前j个字符能匹配出的最长回文串。

对当前s1[i]和s2[j]

如果i和j能匹配也就是s1[i]==s2[j],f[i][j]=f[i-1][j-1]+1;

否则的话f[i][j]=max(f[i-1][j],[i][j-1]);

(因为字符串长度只有5000,5000*5000不会炸内存,所以懒得去想压成一维数组了...当然想压的话不难...压不成一维压成f[2][n]还不是一眼就看出来的事情.....)

【代码】

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
char s1[5001],s2[5001];
int f[5010][5010];
int main()
{
while(~scanf("%s",s1))
{
int len=strlen(s1);
for(int i=len-1;i>=0;i--)s2[len-i-1]=s1[i];
//printf("%s\n%s",s1,s2);
memset(f,0,sizeof(f));
for(int i=1;i<=len;i++)
for(int j=1;j<=len;j++)
if(s1[i-1] == s2[j-1])
f[i][j]=f[i-1][j-1]+1;
else
f[i][j]=max(f[i-1][j],f[i][j-1]);
printf("%d\n",len-f[len][len]);
}
return 0;
}