题目连接:http://poj.org/problem?id=3280
题意:给定一个长度为m(m<=2000)的小写字母字符串,在给定组成该字符串的n(n<=26)个字符的添加和删除费用,求使原字符串变为回文串的最小费用。
分析:首先明确,删除一个字母和增加一个字母是等价的,如果删除一个字符一个字符使得原字符串变成回文,那么必定可以增加一个字符使原字符串变成回文,因此对于删除和增加操作去费用最少的即可。
dp[i][j]表示区间i~j形成回文串最少费用,则:
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]);
#include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #define LL long long #define mod 100000000 #define inf 0x3f3f3f3f #define eps 1e-9 #define N 100010 #define FILL(a,b) (memset(a,b,sizeof(a))) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; int cost[30],dp[2110][2110]; char s[10],str[2100]; int dfs(int l,int r) { if(dp[l][r]!=-1)return dp[l][r]; if(l>=r)return 0; int temp=inf; if(str[l]==str[r]) temp=min(temp,dfs(l+1,r-1)); temp=min(temp,dfs(l+1,r)+cost[str[l]-'a']); temp=min(temp,dfs(l,r-1)+cost[str[r]-'a']); return dp[l][r]=temp; } int main() { int n,m; while(scanf("%d%d",&n,&m)>0) { scanf("%s",str+1); for(int i=1;i<=n;i++) { int add,det; scanf("%s%d%d",s,&add,&det); cost[s[0]-'a']=min(add,det); } FILL(dp,-1); printf("%d\n",dfs(1,m)); } }