【poj 3280】 Cheapest Palindrome 题意&题解&代码(C++)

题目链接:
http://poj.org/problem?id=3280
题意:
给出一个字符串,要求将其修改成一个回文字符串,给出修改某种字母(添加或删除)的价值,求最小使其成为回文字符串的价值。
题解:
感觉是求最长回文子序列的变形,然而刚开始想着用类似于求最长回文子序列的方法,将字符串反转后与原字符串匹配最长公共子序列,在匹配的过程中来进行dp转移,但发现这样不行,因此还是借鉴了网上的方法用dp[i][j]表示处理完区间将i~j之间的字符串变为回文字符串的最小代价,那么很明显有转移方程

    if (s[i-1]==s[j-1])
    dp[i][j]=dp[i+1][j-1];
    else
    dp[i][j]=min(dp[i+1][j]+cost[ci],dp[i][j-1]+cost[cj]);

还有一点就是其实虽然给出的删除和修改是两个费用,但实际上每次修改时添加和删除的效果是一样的,因此每次都一定会取其中最小的费用,新开一个数组存起来就不用每次比较了。

代码:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
int n,m,cost[2005],dp[2005][2005];
char s[2005];
int main()
{
    scanf("%d%d",&n,&m);
    scanf("%s",s);
    for (int i=1;i<=n;i++)
    {
        char c[2];
        int a1,a2;
        scanf("%s%d%d",c,&a1,&a2);
        cost[c[0]-'a']=min(a1,a2);
    }
    //for (int i=1;i<=m;i++)
    //for (int j=1;j<=m;j++)
    //dp[i][j]=1e9+7;
    //for (int i=1;i<=m;i++)
    //dp[i][i]=0;
    //此题中不需要给dp初始化,因为每一个(i,j)(i<j)只会被枚举到一次
    for (int i=m;i>=1;i--)
    for (int j=i+1;j<=m;j++)
    if (s[i-1]==s[j-1])
    //如果j=i+1时我们发现i+1>j-1有没有必要特判一下呢,并不需要。
    dp[i][j]=dp[i+1][j-1];
    else
    {
        int ci=s[i-1]-'a';
        int cj=s[j-1]-'a';
        dp[i][j]=min(dp[i+1][j]+cost[ci],dp[i][j-1]+cost[cj]);
    }
    printf("%d\n",dp[1][m]);
}

你可能感兴趣的:(dp,poj)