poj 3280 Cheapest Palindrome (dp)

http://poj.org/problem?id=3280

又是一道 dp 题目 一开是 有点 小思路,认为他就是括号匹配的变形吗,可是后来,越想月觉的麻烦,(后来才知道 自己 向的太多了,)

一开始 认为他 可以  在任意位置 插入和删除 有一定的费用 ,怎么个dp 法呀,后来看了解题报告 ,确实和 括号匹配一样,

我太菜了。。。。

题意: 一个字符串          求将其 变为回文串的最小花费 ,每个 字母  添加 和删除 都要一定的花费;

dp[i][j] 表示  将 str[i    -----j] 变为   回文串的最小花费

if(str[i] == str[j])   dp[i][j] = dp[i + 1][ j - 1];

els

{

     dp[i][j] = min(dp[i + 1][j] + min(add[str[i] - 'a'],dele[str[i ]- 'a']),dp[i][j -1] + min(add[str[j]- 'a'],dele[str[j ]- 'a']))  ;

}

转自别处:

其实dp很难逃出3种思路:

1、一维线性dp:每次考虑i时,选择最优子问题要么在i-1,要么在1...i-1里;

2、二维线性dp:考虑(i,j)子问题时,选择最优子问题要么在(i+1,j)、(i,j-1),要么在i<= k <=j,在k里;

3、树形dp:考虑i节点最优时,选择子节点最优,一般融合了01背包dp的双重dp。

上面3中模式也是我在做题后才发现的。

这个dp题其实就可以仿照第2中思路。

假设一个字符串Xx....yY;对于求这个字符串怎么求呢?

分4中情况讨论:

1、去掉X,取x....yY回文;

2、去掉Y,取Xx....y回文;

3、在左边加上X,取Xx....yYX回文;

4、在右边加上Y,取YXx....y回文。

至于去掉X、Y肯定没有第1、2中情况合算;加上X、Y肯定没有第3、4中情况合算。

因此令dp[i][j]为i...j要变成回文字符串的最小代价。

方程:

dp[i][j] = min{  dp[i+1][j] + {去掉X的代价},dp[i+1][j] + {加上X的代价},

                                                           dp[i][j-1]+ {去掉Y的代价},dp[i][j-1] +{加上Y的代价}};

其实分析发现,对于X而言,只要去 去掉 和加上 X 最小代价就行(因为前面dp串一样),Y同理。

因此最后得出:

dp[i][j] = min{  dp[i+1][j] +min{ {去掉X的代价}, {加上X的代价}},

                                                           dp[i][j-1]+min{ {去掉Y的代价}, {加上Y的代价}}};

dp时候还有些注意事项:

比如当X和Y字符一样时,则在dp时必须先为x...y的最小代价。

读取时也应注意。

 1     #include<cstdio>
 2     #include<cstring>
 3     #include<cmath>
 4     #include<iostream>
 5     #include<algorithm>
 6     #include<set>
 7     #include<map>
 8     #include<queue>
 9     #include<vector>
10     #include<string>
11     #define Min(a,b) a<b?a:b
12     #define Max(a,b) a>b?a:b
13     #define CL(a,num) memset(a,num,sizeof(a));
14     #define maxn  2050
15     #define eps  1e-6
16     #define inf 9999999
17     #define mx 1<<60
18 
19     using namespace std;
20     int add[maxn],dele[maxn];
21     int dp[maxn][maxn];
22     char str[maxn];
23     int main()
24     {
25         int  n , m,i,j ;
26         char c[3];
27         //freopen("dada.in","r",stdin);
28         while(~scanf("%d%d",&n,&m))
29         {
30             scanf("%s",str);
31             for(i = 0; i < n; ++i)
32             {
33                 scanf("%s",c);
34                 scanf("%d %d",&add[c[0] - 'a'],&dele[c[0] - 'a']);
35             }
36             int len = strlen(str);
37 
38             CL(dp,0);
39 
40             for( i = len - 2 ; i >= 0  ; -- i)
41             {
42                 for( j = i + 1; j < len ; ++j)
43                 {
44                     if(str[i] == str[j])  dp[i][j] =  dp[ i + 1][ j  - 1];
45                     else
46                     {
47                         dp[i][j] = min(dp[i + 1][j] + min(add[str[i] - 'a'],dele[str[i ]- 'a']),dp[i][j -1] + min(add[str[j]- 'a'],dele[str[j ]- 'a']))  ;
48                     }
49                 }
50             }
51 
52 
53             printf("%d\n",dp[0][len - 1]);
54 
55         }
56         return 0 ;
57     }
原文地址:https://www.cnblogs.com/acSzz/p/2633509.html