POJ3280——Cheapest Palindrome(动态规划)

来源:互联网 发布:淘宝贷款怎么随借随带 编辑:程序博客网 时间:2024/06/09 22:50

题目链接

       题目意思挺好懂的,就是说给你一个字符串,要求添加或删除若干的字符使得其成为回文串。给出每个字符添加和删除的代价,求出代价最小值。简单的DP,方程为:dp[i][j]=min(dp[i][j-1]+Map[s[j]-'a'],dp[i+1][j]+Map[s[i]-'a']);dp[i][j]表示第i个字符到第j个字符的最小代价,Map[s[i]-'a']表示删除或添加第i个字符的最小代价,因为实现的是每一步的对称,所以删除和添加实际上是为了达到同样的效果,所以直接取其删除或添加的最小值作为代价。代码已给出,但有一点需注意:那就是DP的顺序,,,第一层i的循环应该从L-1到0,而第二层循环应该从i+1到L-1。不然会wrong的。

       至于原因,第二层还是蛮好理解的,但第一层呢~~,可以这样想一下,假设i从是从0到L-1,那么,dp[0][l-1]按照方程就是由dp[i][j-1]和dp[i+1][j]等参数决定的,但这个方程成立的前提是dp[i][j-1]和dp[i+1][j]已经最优,也就是最优子结构。但实际上dp[i+1][j]还没有被计算过,也就是dp[i+1][j]并未被计算过,也就是这并非最优子结构,所以i的循环顺序只能从L-1到0,这样才能保证dp[i+1][j]是最优的子结构。



#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<algorithm>using namespace std;typedef long long LL;LL Map[30]={0};char s[2010]={0};LL dp[2005][2005]={0};int main(){    //freopen("in.in","r",stdin);    int n, l;    scanf("%d%d",&n,&l);    char c=getchar();    scanf("%s",s);    c=getchar();    for(int i=1;i<=n;i++)    {        LL a, b;        scanf("%c%lld%lld",&c,&a,&b);        Map[c-'a']=min(a,b);        c=getchar();    }    for(int i=l-1;i>=0;i--)//切记dp的顺序i应该从l-1到0.        for(int j=i+1;j<l;j++)    {        if(s[i]==s[j])dp[i][j]=dp[i+1][j-1];        else dp[i][j]=min(dp[i][j-1]+Map[s[j]-'a'],dp[i+1][j]+Map[s[i]-'a']);//DP方程.    }    printf("%lld\n",dp[0][l-1]);    return 0;}


0 0