题目链接:http://poj.org/problem?id=3280
题目大意:有一个字符串由N(1<=N<=26)种小写字母组成,长度为M(1<=M<=2000),
在字符串中任意位置添加或删除字母使字符串变成一个回文串,添加和删除有一定的花费。求这个最小花费。
动态规划策略:设dp[i][j]为字符串从 i 到 j 成为回文串的最小花费。
dp[i][j]可能由三种状态转移过来:
在头部添加一个:dp[i+1][j]+cost[i]
在尾部添加一个:dp[i][j-1]+cost[j]
不添加:dp[i+1][j-1] if ( str[i] == str[j] )
使用双层循环遍历 所有的(i,j),复杂度为O(M^2)。
Sample Input
3 4 abcb a 1000 1100 b 350 700 c 200 800
Sample Output
900
Hint
If we insert an "a" on the end to get "abcba", the cost would be 1000. If we delete the "a" on the beginning to get "bcb", the cost would be 1100. If we insert "bcb" at the begining of the string, the cost would be 350 + 200 + 350 = 900, which is the minimum.
下面是已AC的代码:
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
string str;
struct ST{
char ch;
int add, del;
} st[30];
int chp[30];
int dp[2010][2010]; // dp[i][j]:字符串从i到j为回文串的代价
int main()
{
int N, M;
cin >> N >> M;
cin >> str;
for ( int i = 0 ; i < N ; ++ i ) {
cin >> st[i].ch >> st[i].add >> st[i].del;
chp[st[i].ch-'a'] = min(st[i].add, st[i].del);
}
for ( int i = 1 ; i < M ; ++ i ) {
for ( int j = i-1 ; j >= 0 ; -- j ) {
// 头部变化 或尾部变化
dp[j][i] = min(dp[j+1][i]+chp[str[j]-'a'], dp[j][i-1]+chp[str[i]-'a']);
// 如果相等则可能没有变动字符
if ( str[i] == str[j] ) dp[j][i] = min(dp[j][i], dp[j+1][i-1]);
}
}
cout << dp[0][M-1] << endl;
return 0;
}