题目链接:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16272
题意:
给一个字符串和每个字符的权值,问最小代价通过删除或者增加任意位置字符使得字符变为回文串。
思路:
区间DP,毫无意外的看了题解。具体的话每次增加一个字符,增加代价为头字符和尾字符代价的最小值。当头尾相等时,即data[i]==data[j]时,dp[i][j] =gmin(dp[i+1][j-1])。
算是革新思想的一题。区间DP的关键是大区间化简为小区间,而不是中间区间的更新过程。实际上更新过程因题而异,有的从头,有的从尾;有的遍历中间点,有的只看头尾两点。关键是要理解增添区间的过程,以及区间封装的数值相互影响的关系。说得有些抽象,重点就是大区间化为小区间,其他的灵活处理。
源码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <queue>
using namespace std;
#define gmin(a,b) a<b?a:b
int const MAXN = 2000+5;
int dp[MAXN][MAXN];
int alp[30];
char data[MAXN];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
scanf("%s",data);
getchar();
char c;
int t1,t2;
memset(dp,0,sizeof(dp));
memset(alp,0,sizeof(alp));
for(int i=0; i<n; i++){
scanf("%c %d %d",&c,&t1,&t2);
alp[c-'a'] = gmin(t1,t2);
getchar();
// printf("for i = %d,c= %c,t1 =%d,t2 = %d\n",i,c,t1,t2);
}
for(int i=1; i<m; i++){
for(int j=0; j+i<m; j++){
dp[j][j+i] = dp[j+1][j+i-1] +alp[data[j]-'a'] + alp[data[j+i]-'a'];
// for(int k=j+1; k<=j+i; k++){
// if(data[k] == data[j])
// dp[j][j+i] =gmin(dp[j][j+i],dp[j+1][k-1]+dp[k+1][j+i-1]);
dp[j][j+i] =gmin(dp[j][j+i],dp[j+1][j+i]+alp[data[j]-'a']);
dp[j][j+i] =gmin(dp[j][j+i],dp[j][j+i-1]+alp[data[j+i]-'a']);
if(data[j+i] == data[j])
dp[j][j+i] = gmin(dp[j][j+i],dp[j+1][j+i-1]);
// }
}
}
// for(int i=0; i<m; i++){
// for(int j=0; j<m; j++)
// printf("%d",dp[i][j]);
// printf("\n");
// }
printf("%d\n",dp[0][m-1]);
}
return 0;
}