题目大意:给出一个字符串,问至少添加多少个字符才能使它成为回文串?
思路:很明显的方程是:dp[i][j]=min{dp[i+1][j],dp[i][j-1],dp[i+1][j-1](str[i]==str[j]时)}
dp[i][j]表示第i个字符到第j个字符构造成回文串最少添加的字符,但discuss里说了 这样做会超空间+超时
观察下这个方程,每次用到的就是那三个子状态,于是适当的改变方程的形式:
dp[i][j]表示第i个字符开始长度为j的子串构成的字符串最少需要添加的字符,于是方程变成了dp[i][j]=min{dp[i+1][j-1],dp[i][j-1],dp[i+1][j-2](str[i]==str[j]时)},递推时只需储存长度为j-1和j-2的数据就能推出长度为j的数据,利用指针改变下三个数组的顺序即可。于是空间问题顺利解决
//poj1159
#include<cstdio>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn=5009;
int min(int a ,int b)
{
if(a>b)return b;else return a;
}
int main()
{
int n;
char str[maxn];
scanf("%d %s",&n,str);
int a[maxn]={0},b[maxn]={0},c[maxn]={0};
int *ans=a,*f=b,*ff=c,*temp;
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n-k+1;i++)
{
ans[i]=min(f[i],f[i+1])+1;
if (str[i-1]==str[i+k-2])ans[i]=min(ans[i],ff[i+1]);
}
temp=ff;ff=f;f=ans;ans=temp;
}
printf("%d\n",f[1]);
return 0;
}