题意
思路
dp[i][j]保存的是i~j这一段已经是回文且最优解
那么当我们要求新的区段i~j时只需要考虑s[i] ?= s[j]
if(s[i] == s[j]) dp[i][j] = min(dp[i][j],dp[i +1][j - 1]);
else dp[i][j] = min(dp[[i][j],min(dp[i + 1][j] + chan[s[i]],dp[i][j - 1] + chan[s[j]]));
chan数组每个字符min(add,reduce),这是因为当两边s[i] != s[j]时 对于从dp[i +1][j]转化过来 s[i]可以在i这一位舍弃或者s[j]后面补上一个s[i] 因此cost += min(add,reduce) dp[i][j - 1]也是一样的过程
每个dp[i][j]只代表这一段的回文最优解 是无后效性的 直接继承就好不会影响后面的答案
ACcode
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
const int inf = 0x3f3f3f3f;
int n,len;
char op;
char s[2005];
int ad[30],re[30],chan[30];
int dp[2005][2005];
int main()
{
scanf("%d %d",&n,&len);
scanf("%s",s + 1);
s[0] = '#',s[len + 1] = '#';
for(int i = 1;i <= n; i++){
scanf(" %c",&op);
int cur = op - 'a';
scanf("%d %d",&ad[cur],&re[cur]);
chan[cur] = min(ad[cur],re[cur]);
}
memset(dp,0,sizeof dp);
for(int i = 1;i <= len; i++){
for(int j = i;j <= len; j++) dp[i][j] = inf;
}
for(int L = 1;L <= len; L++){
for(int i = 1;i + L - 1 <= len; i++){
int j = i + L - 1;
if(s[i] == s[j]) dp[i][j] = min(dp[i][j],dp[i + 1][j - 1]);
else dp[i][j] = min(dp[i][j],min(dp[i + 1][j] + chan[s[i] - 'a'],dp[i][j - 1] + chan[s[j] - 'a']));
}
}
printf("%d\n",dp[1][len]);
}