区间DP基础篇之 POJ1159——Palindrome

来源:互联网 发布:淘宝成功原因 编辑:程序博客网 时间:2024/05/16 16:05


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

法一:

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 5001using 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);


0 0
原创粉丝点击