题目链接:http://poj.org/problem?id=3280
一个序列,有n种不同的字符,可以在这个序列的任意位置插入和删除字符,花费不同,问最少需要多少花费可以使这个序列变成回文字符串。由于在头部插入和在尾部删除一个字符都能得到一个字符的前后回文对应,所以对于每一种字符只要知道插入和删除的最小操作就可以,插入和删除的操作是等价的。状态的转移在代码中已经表明。
代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<string.h> 4 using namespace std; 5 int n,m; 6 const int maxn=1e6+5; 7 char s[maxn]; 8 int w[30]; 9 int dp[2005][2005]; 10 const int inf=0x7ffffff; 11 int main() 12 { 13 while(~scanf("%d%d",&n,&m)) 14 { 15 scanf("%s",s); 16 for(int i=0;i<n;i++) 17 { 18 char c; 19 int x,y; 20 scanf(" %c%d%d",&c,&x,&y); 21 w[c-'a']=min(x,y);//由于在[i,j]区间的头部插入操作和在尾部删除的效果是一样的所以只需要知道两种操作哪一种的消耗比较小 22 } 23 for(int i=m-1;i>=0;i--)//枚举区间的两个端点 24 { 25 for(int j=i+1;j<=m-1;j++) 26 { 27 if(s[i]==s[j]) 28 { 29 dp[i][j]=dp[i+1][j-1];//字符相等时没有花费 30 } 31 else//不相等时可能有两种花费的情况 32 { 33 dp[i][j]=min(dp[i][j-1]+w[s[j]-'a'],dp[i+1][j]+w[s[i]-'a']); 34 } 35 } 36 } 37 printf("%d ",dp[0][m-1]); 38 } 39 }