首页 > 代码库 > POJ1159:Palindrome【dp】

POJ1159:Palindrome【dp】

题目大意:给出一个字符串,问至少添加多少个字符才能使它成为回文串?

思路:很明显的方程是: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;

}

POJ1159:Palindrome【dp】