poj 3280 Cheapest Palindrome 夜

http://poj.org/problem?id=3280

给一个字符串

可以再任意位置添加或删除字母(给出花费的) 使得字符串变成回文

思路:

其实添加和删除的性质是一样的

添加一个字母和删去相对应的字母 对于使原文变成回文

的贡献是一样的 所以我们取花费的时候 只取小的花费

为了理解方面统一用删除吧

从两端进行遍历

1 如果对应相等 则直接去掉就可以  (无需花费)

2 如果只有一个字符了 直接去掉 (无需花费)

3 否则选择删掉左边 和 删掉右边 两种情况中最优的(只有给出花费才能删)

代码及其注释:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>

using namespace std;

const int N=2005;
char s[N];
int cost[27];
int ans[N][N];//在l 到 r 区间变成回文的最小花费
int dp(int l,int r)
{
    if(ans[l][r]!=-1)//记忆化搜索
    return ans[l][r];
    if(l==r)//只有一个字符
    {
        ans[l][r]=0;
        return ans[l][r];
    }
    if(s[l]==s[r])//左右相等
    {
        if(l+1==r)
        ans[l][r]=0;
        else
        ans[l][r]=dp(l+1,r-1);
        return ans[l][r];
    }
    ans[l][r]=min(cost[s[l]-'a']+dp(l+1,r),dp(l,r-1)+cost[s[r]-'a']);//两种情况选最优
    return ans[l][r];
}
int main()
{
   int n,m;
   while(scanf("%d %d",&n,&m)!=EOF)
   {
       scanf("%s",s);
       memset(cost,-1,sizeof(cost));
       while(n--)
       {
           char c;
           int v1,v2;
           getchar();
           scanf("%c %d %d",&c,&v1,&v2);
           cost[c-'a']=min(v1,v2);
       }
       memset(ans,-1,sizeof(ans));
       printf("%d\n",dp(0,m-1));
   }
   return 0;
}

  

原文地址:https://www.cnblogs.com/liulangye/p/2598160.html