Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 45704 | Accepted: 15580 |
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
Source
题意:给你一个字符串,你可以在这个字符串的任意位置插入一个字符,现在要求最少要插入多少个字符才能使这个字符串变成回文的。
分析:很经典的DP,在刘汝佳的书里也应该有提到这题。这题是我AC的第一个区间dp题,AC这题后自己也对区间dp有了一定的了解。好了,废话不多说了,现在开始讲解法:
对于一个字符串序列S1,S2,S3……Sn 想要将它变成回文的,注意!!不要想得太复杂,其实我们只能在字符串的两端添加字符(这儿要仔细想想,想通了,这题就变得容易了),在字符串当中添加字符是完全没有意义的,所以对于当前的状态,我们只可能遇到2种可能的情况,我们来归纳一下:
1.当S1==Sn时(字符串头字符和字符串尾部字符相等时),我们的任务便转换为了将S2,S3,S4……S(n-1)变成回文,对吗?
2.当S1!=Sn时,我们又有了两种决策
第一种决策:在字符串序列S1,S2,S3……Sn
第二种决策:在字符串序列S1,S2,S3……Sn
根据这个思路,我们很快就能写出递归代码(我加了记忆化):
int DFS(int l,int r){
}
不过我们遇到了一个很严重的问题:字符串的长度是一个小于5000的数字,但是要是字符串的长度到达了5000,我们岂不是要开一个5000*5000的数组吗?一开始我对这个问题也没什么办法,最后听dicuss中说可以把数组的类型开到short就能过,改了以后就过了。当然,这不是正解,正解是用滚动数组,可以将空间从O(n^2)优化到O(n),不失为一个好办法。不过我写得是记忆化DFS,所以不能用滚动数组。
我代码(1922ms AC):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <string>
using namespace std;
char str[5005];
short int dp[5005][5005];
int DFS(int l,int r){
if(l>=r) return 0;
if(dp[l][r]!=-1)
return dp[l][r];
int M=99999999;
if(str[l]==str[r])
M=DFS(l+1,r-1);
else{
M=min(M,DFS(l,r-1)+1);
M=min(M,DFS(l+1,r)+1);
}
return dp[l][r]=M;
}
int main()
{
int len;
while(scanf("%d",&len)!=EOF){
scanf("%s",str+1);
memset(dp,-1,sizeof(dp));
cout<<DFS(1,len)<<endl;
}
return 0;
}
照着原样写了个,惭愧。。。
//Accepted 49400K 1516MS C++ 599B 2013-03-15 19:19:43
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 5000 + 5;
short int dp[maxn][maxn];
char str[maxn];
int dfs(int l, int r)
{
if(l >= r) return 0;
if(dp[l][r] != -1) return dp[l][r];
int M;
if(str[l] == str[r])
{
M = dfs(l+1, r-1);
}
else
{
M = min(dfs(l, r-1) + 1, dfs(l+1, r) + 1);
}
return dp[l][r] = M;
}
int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
memset(str,'0',sizeof(str));
memset(dp,-1,sizeof(dp));
scanf("%s", str+1);
printf("%d\n", dfs(1,n));
}
return 0;
}