题解:
题目的意思是有一个长度为M的字符串,一共包含N个字母,可以在字符串基础上添加或删除字母,使字符串是一个回文串。
题目看起来比较复杂,字符串可增可减,增减的位置还不确定。参考了别人的博客后发现其实增减的效果是一样的,只需要挑最优的一种方法就好了。减去一个字母,效果相当于在一个对应位置加上该字母。
长度为1的本身就是回文串,随着字符串长度不断增加,我们可以选择在字符串两边添加对应字母,所以按照区间dp,遍历区间长度。
dp定义:dp[i][j],长度从i到j的字符串转换为回文串需要的最小代价。
递推关系式:
0.s[i]=s[j]
dp[i][j] = dp[i+1][j-1];
1.s[i]!=s[j]
dp[i][j] = min(左边加s[i],右边加s[j])
代码实现:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
const int MAX_N = 30;
const int MAX_M = 2010;
const int INF = 0x7ffffff;
int N,M;
int add[MAX_N];
char str[MAX_M];
int dp[MAX_M][MAX_M];
int main()
{
scanf("%d%d",&N,&M);
scanf("%s",str);
for( int i = 0; i < N; i++ ){
int a,b;
char tmp;
getchar();
scanf("%c%d%d",&tmp,&a,&b);
add[tmp-'a'] = min(a,b);
}
memset(dp,0,sizeof(dp));
for( int k = 1; k <= M-1; k++ ){
for( int i=0,j=k; j < M; i++,j++ ){
dp[i][j] = INF;
if( str[i] == str[j] ){
dp[i][j] = dp[i+1][j-1];
}
else{
int left = str[i]-'a';
int right = str[j]-'a';
dp[i][j] = min(dp[i][j],min(dp[i+1][j]+add[left],dp[i][j-1]+add[right]));
}
}
}
printf("%d\n",dp[0][M-1]);
return 0;
}