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 }