Description
小B的名字是由前n个小写字母组成的一个长度为m字符串。一天,小B看上了一个金发碧眼的漂亮妹子,但妹子在知道了小B的名字后,就无情地抛弃了小B,而原因竟然是小B的名字不够优美!在小B的追问下,妹子告诉小B,只有回文串是优美的。于是小B决定把自己的名字变得优美,但每加入或删除一个字母都要付出一定的代价。为了小B的人生大事,请你告诉小B他最少需要付出多少代价。
Input
第一行两个数分别表示n和m。
第二行是一个长度为m的字符串,仅由前n个小写字母组成。
接下来n行,每行含有一个字母和两个正整数,表示添加和删除这个字母的费用。
Output
一行一个整数,表示最小费用。
Sample Input
3 4
abbc
a 10 10
b 20 20
c 30 30
Sample Output
40
Hint
【数据规模与约定】
对于前30%的数据,m <= 10
对于前50%的数据,m <=100
对于前100%的数据,n<=26,m<=2000,0<=费用<=10000
思路
在草稿本上列一下就发现其实添加和删除是一样的效果,然后就直接可以看出来是动规了。
状态转移方程:f[i][j]=min(f[i+1][j]+a[s[i]],f[i][j-1]+a[s[j]]);
if(s[i]==s[j]) f[i][j]=min(f[i][j],f[i+1][j-1]);
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
# define N 2000
using namespace std;
int n,m;
int a[26],f[N][N];
char ch;
char s[N];
int main()
{
freopen("ya.in","r",stdin);
freopen("ya.out","w",stdout);
scanf("%d%d" ,&n,&m);
scanf("%s" ,s+1);
int x=0,y=0;
for(int i=1;i<=n;i++)
{
scanf("%c" ,&ch);
scanf("%c" ,&ch);
scanf("%d%d" ,&x,&y);
a[ch]=min(x,y);
}
for(int i=m-1;i>=1;i--)
for(int j=i+1;j<=m;j++)
{
f[i][j]=min(f[i+1][j]+a[s[i]],f[i][j-1]+a[s[j]]);
if(s[i]==s[j]) f[i][j]=min(f[i][j],f[i+1][j-1]);
}
printf("%d\n" ,f[1][m]);
fclose(stdin);
fclose(stdout);
}