POJ3280 Cheapest Palindrome

题意:一个字母序列长度为 m ,由 n 个字母组成,每个字母有两个花费:① 删掉这个字母;② 加上这个字母。问把这个序列变成一个回文序列的最小花费。

题解:F[ i ][ j ] 表示 i - j 这一段变成回文串的最小花费。

   当序列 s[ i ] == s[ j ] 时,不需要任何花费:F[ i ][ j ] = F[ i + 1][ j - 1];

   否则:① -> 加上或减去第 i 个字母,F[ i + 1 ][ j ] + w[s[ i ]];

      ② -> 加上或减去第 j 个字母,F[ i ][ j - 1 ] + w[s[j]];

      (因为加上或删去一个字母是等效的,那么代价在读入的时候取最小就可以了)

CODE:

/*
Author: JDD
PROG: poj3280 Cheapest Palindorome
DATE: 2015.10.9
*/ 

#include <cstdio>
#define REP(i, s, n) for(int i = s; i <= n; i ++)
#define REP_(i, s, n) for(int i = n; i >= s; i --)
#define MAX_N 2005

using namespace std;

int n, m, F[MAX_N][MAX_N], w[30];
char s[MAX_N];

inline int read()
{
    char c = getchar();
    while(!(c >= '0' && c <= '9')) c = getchar();
    int ret = 0;
    while(c >= '0' && c <= '9') ret = ret * 10 + c - '0', c = getchar();
    return ret;
}

#define min(a, b) (a < b ? a : b)

inline void init()
{
    n = read(); m = read();
    scanf("%s", s + 1);
    getchar();
    char c; int x, y;
    REP(i, 1, n){
        scanf("%c%d%d", &c, &x, &y);
        getchar();
        w[c - 'a' + 1] = min(x, y);
    }    
}

inline void doit()
{
    REP_(i, 1, m - 1) REP(j, i + 1, m){
        if(s[i] == s[j]) F[i][j] = F[i + 1][j - 1];
        else F[i][j] = min(F[i + 1][j] + w[s[i] - 'a' + 1], F[i][j - 1] + w[s[j] - 'a' + 1]);
    }
    printf("%d\n", F[1][m]);
}

int main()
{
    init();
    doit();
    return 0;
}

 

   

posted @ 2015-10-09 16:20  ALXPCUN  阅读(196)  评论(0编辑  收藏  举报