http://poj.org/problem?id=3280
对字符串进行增删操作使其形成回文串,每次操作都有其对应的花费,求最小花费。
典型DP,dp[i][j]为使str[j, i]形成回文的最小花费。
若str[j]==str[i],则dp[i][j]由dp[i-1][j+1]而来。
若str[j]!=str[i],则dp[i][j]=min(dp[i-1][j]+v[data[i]], dp[i][j+1]+v[data[j]]) ;v[data[j]]为增减字符j所花费最小值,因为增加一个字符和减少一个字符起到的效果是相同的,所以预处理出数组v即可。
练习赛时就是没想到预处理这一点而没敢去做。
code:
#include<iostream>//增加和删除的效果一样
#include<cstdio>
#include<cstring>
using namespace std ;
int dp[2001][2001] ;
int v[30], vt[30] ;
int data[2001] ;
char c[2001] ;
int min(int a, int b){
return a<b ? a:b ;
}
int main(){
int i, j, n, m ;
char d ;
scanf("%d%d", &n, &m) ;
scanf("%s", c) ;
for(i=0; i<m; i++)
data[i] = c[i] - 'a' ;
for(i=0; i<n; i++){
scanf("%s", c) ;
scanf("%d%d", &v[c[0]-'a'], &vt[c[0]-'a']) ;
v[c[0]-'a'] = min(v[c[0]-'a'], vt[c[0]-'a']) ;
}
for(i=1; i<m; i++){
for(j=i-1; j>=0; j--){
if(data[i]==data[j])
dp[i][j] = dp[i-1][j+1] ;
else
dp[i][j] = min(dp[i-1][j]+v[data[i]], dp[i][j+1]+v[data[j]]) ;
}
}
printf("%d\n", dp[m-1][0]) ;
return 0 ;}
#include<cstdio>
#include<cstring>
using namespace std ;
int dp[2001][2001] ;
int v[30], vt[30] ;
int data[2001] ;
char c[2001] ;
int min(int a, int b){
return a<b ? a:b ;
}
int main(){
int i, j, n, m ;
char d ;
scanf("%d%d", &n, &m) ;
scanf("%s", c) ;
for(i=0; i<m; i++)
data[i] = c[i] - 'a' ;
for(i=0; i<n; i++){
scanf("%s", c) ;
scanf("%d%d", &v[c[0]-'a'], &vt[c[0]-'a']) ;
v[c[0]-'a'] = min(v[c[0]-'a'], vt[c[0]-'a']) ;
}
for(i=1; i<m; i++){
for(j=i-1; j>=0; j--){
if(data[i]==data[j])
dp[i][j] = dp[i-1][j+1] ;
else
dp[i][j] = min(dp[i-1][j]+v[data[i]], dp[i][j+1]+v[data[j]]) ;
}
}
printf("%d\n", dp[m-1][0]) ;
return 0 ;}