Cheapest Palindrome POJ - 3280【dp-区间dp 回文】

传送门

来自vjudge的题意


分析

定义状态:dp[i][j] 为把区间i~j变成回文的最小代价


转移:
s[i]==s[j] dp[i][j]=dp[i+1][j-1]
如果 s[i+1]~s[j]是回文串 则对于s[i]可以增加可以删除,dp[i][j]=dp[i+1][j]+min(ac(s[i]),dc(s[i]))
如果 s[i]~s[j-1]是回文串 则对于s[j]可以增加可以删除,dp[i][j]=dp[i][j-1]+min(ac(s[j]),dc(s[j]))

(有同志问为什么dp[i+1][j]可以对应条件 如果 s[i+1]~s[j]是回文串 其实就是对于dp[i+1][j],既然它都表示变成回文的代价了,那这个区间就是回文,如果它已经计算过,就可以直接转移 这是dp呐 不是说要判断它是否回文,利用这样的思路计算代价而已 如果你没有这样的疑问,请略过此处


这几种情况取min
由于dp[i][j]要从dp[i+1][j-1]、dp[i+1][j]、dp[i][j-1]中转移过来,所以i反着枚举,j正着枚举
几种情况取min dp[i][i]要置为0(一个字符本身就是回文)

考虑到对于一个字符增加和删除对结果并没有什么影响,所以只要对这个字符有改动就用增加的删除中的小的代价
那么在存储时可以只存ac和dc中小的那一个


#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXM 2010
#define INF 0x3f
int n,m;
char s[MAXM];
int c[26];
int dp[MAXM][MAXM];//区间i~j的最小代价
int main()
{
    scanf("%d %d",&n,&m);
    scanf("%s",s);//从0开始!!!
    for(int i=1;i<=n;i++)
    {
        char tmp[5];//有换行符,非常非常非常非常非常坑!!!
        int x,y;
        scanf("%s",tmp);
        scanf("%d %d",&x,&y);
        c[tmp[0]-'a']=min(x,y);
    }
    for(int i=m-1;i>=0;i--)
    {
        dp[i][i]=0;
        for(int j=i+1;j<m;j++)
        {
            dp[i][j]=INF;//之前用memset和fill全局清都WA了,至今未果,还是不要随便全局了,只清要比较的qwq
            if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1];
            dp[i][j]=min(dp[i][j],dp[i+1][j]+c[s[i]-'a']);
            dp[i][j]=min(dp[i][j],dp[i][j-1]+c[s[j]-'a']);
        }
    }
    printf("%d\n",dp[0][m-1]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/CQBZLYTina/article/details/81485619