POJ3280——Cheapest Palindrome(動態規劃)

題目鏈接

       題目意思挺好懂的,就是說給你一個字符串,要求添加或刪除若干的字符使得其成爲迴文串。給出每個字符添加和刪除的代價,求出代價最小值。簡單的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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章