题目翻译(借鉴自@ 神犇的蒟蒻)
【问题描述】
追踪每头奶牛的去向是一件棘手的任务,为此农夫约翰安装了一套自动系统。他在每头牛身
上安装了一个电子身份标签,当奶牛通过扫描器的时候,系统可以读取奶牛的身份信息。
目前,每个身份都是由一个字符串组成的,长度为M (1 ≤ M ≤ 2000),所有的字符都取自N个
小写字母。奶牛们都是顽皮的动物,有时它们会在通过扫描器的时候倒着走,这样一个原来身份为
abcb 的奶牛就可能有两个不同的身份了(abcb 和 bcba),而如果身份是 abcba 的话就不会有这个
问题了。约翰想改变奶牛们的身份,使他们不管怎么走读起来都一样。比如说,abcb可以在最后加个 a,变成回文 abcba;也可以在前面加上 bcb,变成回文 bcbabcb;或者去除字母 a,保留的 bcb 也是一条回文。总之,约翰可以在任意位置删除或插入一些字符使原字符串变成回文。不巧的是,身份标签每增加或删除一个字母都要付出相应的费用(0 ≤ 费用代价 ≤ 10000)。给定一头奶牛的身份标签和增加或删除相关字母的费用,找出把原来字符串变成回文字符串的最小费用。注意空字符串也是回文。
【输入】
第一行:两个用空格分开的整数:N和M。
第二行:一个长度恰好为M的字符串,代表初始的身份标签。
第三行到第N + 2行:每行为一个用空格分开的三元组:其中包括一个字符和两个整数,分别
表示增加或删除这个字符的费用。
【输出】
只有一个整数,表示改造这个身份标签的最小费用。
当然,原文可见 传送门
这里是代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m,a[2001],w[27];
int dp[2001][2001];
int main() {
/*
设[l,r]为已经求得最优解的子串,若使[l,r+1]也为回文字串有
i. 删除[l,r+1]中的a[l+r]字符
ii. 在[l,r]的左边加上一个a[l+r]字符
故最小花费为min(del[a[r+1]],add[a[r+1]])
同理可得,使[l-1,r]的最小花费为min(del[a[l-1]],add[a[l-1]])
并且,若在a[l-1]==a[r+1]可以确定[l-1,r+1]在[l,r]的基础上不需要花费。
*/
char in;
scanf("%d%d\n",&n,&m);
for(int i=1; i<=m; i++) {
scanf("%c",&in);
a[i]=in-'a';
}
for(int i=1,x1; i<=n; i++) {
scanf("\n%c",&in),in-='a';
scanf("%d%d",&w[in],&x1);
if(x1<w[in]) w[in]=x1;
}
memset(dp,0x3f,sizeof dp);
for(int i=1; i<=m; i++) {
dp[i][i]=0;
if(a[i]==a[i+1]) dp[i][i+1]=0;
}
for(int ln=1; ln<=m; ln++) {
for(int l=1,r; l+ln-1<=m; l++) {
r=l+ln-1;
if(a[l-1]==a[r+1]) dp[l-1][r+1]=min(dp[l-1][r+1],dp[l][r]);
dp[l-1][r]=min(dp[l-1][r],dp[l][r]+w[a[l-1]]);
dp[l][r+1]=min(dp[l][r+1],dp[l][r]+w[a[r+1]]);
}
}
printf("%d\n",dp[1][m]);
return 0;
}
太棒了。。