POJ3280(DP)

题目大意是说一个字符串,每插入或者删除一个字符都需要一定的代价,问怎样可以使这个字符串变成一个回文串,且花费最小。

首先明确的就是如果已经将区间[i,j]整理成为一个回文串(不管中间有多少个字符或者是以什么字符开头或者结尾),当DP到区间[i,j+1]时,我们可以在i-1的位置添加一个str[j+1]字符,或者将在j+1处的字符删除,得到一个新的回文串,而且我们这两步操作都没有借助或者影响区间[i,j]的情况。

因此,那我们就可以将添加或者删除整合在一起,对字符str[j+1]的操作就按照添加和删除中花费最小的一个计算。写出状态转移方程:

          DP[j][i] = MIN(DP[j+1][i]+cost[str[j]-'a'], DP[j][i-1]+cost[str[i]-'a']);
          if(str[i] == str[j])DP[j][i] = MIN(DP[j][i],DP[j+1][i-1]);

这里的j是按照i-1到0枚举的,由于可能str[i] == str[j],因此也可以不操作,再将  不操作  与  添加或删除区间头或尾  比较。

当然,其实最初的想法是扩展出来四个状态,就是首删除,首添加,尾删除,尾添加,由此扩展开来求一个最小值

 1 #include <stdio.h>
 2 #include <string.h>
 3 #define mem(a) memset(a,0,sizeof(a))
 4 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 5 
 6 int DP[2005][2005],cost[30],N,M;
 7 char str[2005];
 8 
 9 int main()
10 {
11     while(~scanf("%d%d", &M, &N))
12     {
13         mem(DP); mem(str); mem(cost);
14         scanf("%s%*c",str);
15         char ch; int x, y;
16         for(int i=0;i<M;i++)
17         {
18             scanf("%c %d %d%*c", &ch, &x, &y);
19             cost[ch-'a'] = MIN(x,y);
20         }
21         for(int i=1;i<N;i++)
22         {
23             for(int j=i-1;j>=0;j--)
24             {
25                 DP[j][i] = MIN(DP[j+1][i]+cost[str[j]-'a'], DP[j][i-1]+cost[str[i]-'a']);
26                 if(str[i] == str[j])DP[j][i] = MIN(DP[j][i],DP[j+1][i-1]);
27             }
28         }
29         printf("%d\n", DP[0][N-1]);
30     }
31     return 0;
32 }

 

posted @ 2013-08-18 17:32  再见~雨泉  阅读(1996)  评论(1编辑  收藏  举报