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; }