题目:
小码妹是一个喜欢字符串的女孩子。小码妹有一个长度为n的字符串s和一个大小为m的字符集。现在小码妹希望通过在s两端增加或删去字符,使得s变为一个回文串。
但是增加或删去不同字符需要花费的代价不同。小码妹希望花费最少的代价达成目标,于是她想寻求你的帮助。
格式:
输入格式:第一行两个整数m和n,分别表示字符集大小和s的长度。
第二行为字符串s。
接下来m行,每行由一个字符c(数据保证字符c唯一) 和两个整数x,y组成,之间用空格隔开,表示在s两端增加字符c需要x的代价,删去字符c需要y的代价。
输出格式:输出一个整数,表示将 s 变为回文串需要的最小代价。
样例1:
输入:3 4
abcb
a 1000 1100
b 350 700
c 200 800
输出:900
备注:测试数据保证1<=m<=26,1<=n<=2000,1<=x,y<=10000且字符集为小写英文字母的子集
解析:
首先删除和添加其实是一个操作,对回文的操作没有影响,所以cost选择添加和删除里边代价小的一个,设dp[i][j]是 i 到 j 的代价,则状态转移就是
dp[i][j]=min(dp[i+1][j]+cost[i],dp[i][j-1]+cost[j])
如果str[i]==str[j],dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
代码:
#include<stdio.h>
#include <string.h>
#define min(x,y) (x)<(y)?(x):(y)
int dp[2005][2005];
int cost[30];
int main()
{
char str[2005];
int n,m,i,j;
scanf("%d %d %s",&n,&m,str);
char c;int add,del;
for(i=0;i<n;i++){
scanf(" %c %d %d",&c,&add,&del);
cost[c-'a']=min(add,del);
}
memset(dp,0,sizeof(dp));
for(j=1;j<m;j++)
for(i=j-1;i>=0;i--){
dp[i][j]=min(dp[i+1][j]+cost[str[i]-'a'],dp[i][j-1]+cost[str[j]-'a']);
if(str[i]==str[j])
dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
}
printf("%d\n",dp[0][m-1]);
return 0;
}