区间DP基础篇之 POJ1159——Palindrome


题目大意:给定一个字符串,求最少插入几个字符让该字符串成为回文串

法一:

dp[i][j]表示使区间[i,j]成为回文串最小插入的字符数,则状态转移方程

1、if s[i]==s[len-1] 则:d[i][j]=d[i+1][j-1]

2、else  d[i]=min(dp[i+1][j],dp[i][j-1])  

首尾字符不同的时候,有两种决策

1、将新字符插在首位,那么状态就变成了dp[i+1][j]了。

2、将新字符插在末尾,则状态就变成了dp[i][j-1]了 。比较两种决策哪种更优就好啦

别忘了初始化边界~memset(dp,0,sizeof dp);



题目限制的内存是6*10的7次方字节



贴代码环节~~~:

<span style="font-size:18px;">#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define maxn 5001
using namespace std;
short  dp[maxn][maxn];          //本来用的int,4*25*10的6次方等于10的8次方 爆了 ,操了一下下度娘,用short~搜噶
char s[maxn];
int n;
int main()
{
    cin>>n;
    scanf("%s",s);
    memset(dp,0,sizeof(dp));
    int l=strlen(s);
    for(int p=1;p<=l;p++){
        for(int i=0;i<=l-p;i++){
            int j=i+p-1;
            if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1];
            else{
                dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1;
            }
        }
    }
    cout<<dp[0][l-1]<<endl;

    return 0;
}</span>


法二

度娘告诉我说,这题可以用最长公共子序列来搞,就是将字符串逆序,求原字符串和逆序后的字符串的LCS的长度,原字符串的长度减去最长公共子序列的长度,就是所求的最小插入数

最长公共子序列的公式为:
dp[i][j]=max(dp[i-1] [j],dp[i][j-1])
if(a[i]==b[i])
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);

然后就可以用滚动数组啦,因为当前状态dp[i][j],只用到了dp[i-1][0...n]和dp[i][0....n]这两个状态,没有涉及到dp[i-2][0..n]的状态

所以i%2走起,原状态转移方程变为

dp[i%2][j]=max(dp[(i-1)%2] [j],dp[i%2][j-1])
if(a[i]==b[i])
dp[i%2][j]=max(dp[i%2][j],dp[(i-1)%2][j-1]+1);


你可能感兴趣的:(区间DP基础篇之 POJ1159——Palindrome)