POJ 3280 Cheapest Palindrome 区间dp

题意:给你一个字符串和每个字符添加和删除的花费,可以在任一位置添加或者删除字符,求使字符串变成回文串的最小花费。

思路:dp[i][j]表示i~j区间变成回文串的最小花费,假设现在要求dp[i][j],已知比他小区间的所有最优值。

则 : dp[i][j] 在 dp[i][j]删除头部构成的回文串dp[i+1][j] + delete[ s[i] ] 和  dp[i][j]添加尾部构成的回文串dp[i+1][j] + add[ s[i] ] 中取最小值。

同理:dp[i][j] 在 dp[i][j]删除尾部构成的回文串dp[i][j-1] + delete[ s[j] ] 和  dp[i][j]添加头部构成的回文串dp[i][j-1] + add[ s[j] ] 中取最小值。

如果 : s[i] == s[j] , 则s[i][j]在s[i+1][j-1]基础上两端已经是一个回文了,dp[i][j] = min(dp[i][j],dp[i+1][j-1])

状态转移方程:

if(s[i] == s[j]) dp[i][j] = min(dp[i][j],dp[i+1][j-1])

dp[i][j] = min(dp[i][j],dp[i+1][j]+add[s[i]]);

 dp[i][j]= min(dp[i][j],dp[i][j-1]+add[s[j]]);

代码:(以区间为循环条件)

    #include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int add[200];
int dp[2009][2009];
char s[2009];
int main()
{
    int N,M;
    scanf("%d%d",&N,&M);
    cin>>(s+1);
    for(int i = 1; i<=N; i++)
    {
        char ch;
        int a,b;
        cin>>ch>>a>>b;
        add[ch] = min(a,b);
    }
    for(int i = 1; i<=M; i++)dp[i][i] = 0;
    for(int l = 1; l<=M; l++)
    {
        for(int i = 1; i+l<=M+1; i++)
        {
            int j= i+l-1;
            dp[i][j] = 0x3f3f3f3f;//无穷大初始化必须写在这,很迷很迷
            if(s[i]==s[j])dp[i][j] = dp[i+1][j-1];
            dp[i][j]= min(dp[i][j],dp[i+1][j]+add[s[i]]);
            dp[i][j]= min(dp[i][j],dp[i][j-1]+add[s[j]]);

        }
    }
    printf("%d\n",dp[1][M]);
    return 0;
} 

不以区间为条件,要知道dp[i][j]就必须知道dp[i+1][j-1]一类,因此起点必须从后往前推,最后求的是dp[1][M]因此,是后面的小区间不断往前合并,代码:

#include<cstdio>  
#include<algorithm>  
#include<cstring>  
#include<cmath>  
#include<string>  
using namespace std;  
int n,m,dp[2009][2009],in[27],de[27];  
char ch[2009];  
int main()  
{  
    scanf("%d%d",&n,&m);  
    scanf("%s",ch);  
    for (int i=1;i<=n;i++)   
    {  
        char c;  
        cin>>c;
        int k1,k2;  
        scanf("%d%d",&k1,&k2);  
        in[c-'a']=k1;de[c-'a']=k2;  
    }  
    for (int i=m-1;i>=0;i--)  //起点后往前推
    {  
        dp[i][i]=0;  
        for (int j=i+1;j<m;j++)  //终点往后推
        {  
            dp[i][j]=0x3f3f3f3f;//因为找最小的,别忘了开始时置为无穷大  
            if (ch[i]==ch[j]) dp[i][j]=dp[i+1][j-1];  
            dp[i][j]=min(dp[i][j],min(dp[i+1][j]+in[ch[i]-'a'],dp[i+1][j]+de[ch[i]-'a']));  
            dp[i][j]=min(dp[i][j],min(dp[i][j-1]+in[ch[j]-'a'],dp[i][j-1]+de[ch[j]-'a']));//三种情况  
            //printf("%d %d %d\n",i,j,dp[i][j]);  
        }  
    }  
    printf("%d",dp[0][m-1]);  
    return 0;  
}  

猜你喜欢

转载自blog.csdn.net/qq_40772692/article/details/80292069
今日推荐