博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
pku 3280 Cheapest Palindrome DP
阅读量:5306 次
发布时间:2019-06-14

本文共 3077 字,大约阅读时间需要 10 分钟。

 

题意:

给定一个长度为m的字符串(都是小写字母) ,求通过添加或者删减若干个字符是原字符串变为回文串的最小代价(这里给出n个字符的删除与添加所需的代价,规定添加和删除的字符串都在给定的这n个字符中);

思路:

只能说自己dp太弱了,以后有时间一定要多练习dp。

这里对字符串从两端开始进行比较如果相同则dp[i][j] = dp[i + 1][j - 1],

如果不同则 dp[i][j] = min(dp[i + 1][j] + min(addv[str[i] -'a'],delv[str[i] - 'a']),dp[i][j - 1] + min(addv[str[j] -'a'],delv[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状态转移方程推出来了之后用记忆化搜索比较好些,于是就写了记忆化搜索:

View Code
#include 
#include
#include
#include
#include
#define maxn 2007#define N 8using namespace std;const int inf = 99999999;int dp[maxn][maxn];char str[maxn];int addv[27],delv[27];int DP(int i,int j){ if (dp[i][j] != 0) return dp[i][j]; if (i >= j) { dp[i][j] = 0; return 0; } if (str[i] == str[j]) dp[i][j] = DP(i + 1,j - 1); else dp[i][j] = min(DP(i + 1,j) + min(addv[str[i] - 'a'],delv[str[i] - 'a']),DP(i,j - 1) + min(addv[str[j] - 'a'],delv[str[j] - 'a'])); return dp[i][j];}int main(){ //freopen("d.txt","r",stdin); int n,m,i; char ch[3]; int a,b; scanf("%d%d",&n,&m); scanf("%s",str); for (i = 0; i < n; ++i) { scanf("%s%d%d",ch,&a,&b); addv[ch[0] - 'a'] = a; delv[ch[0] - 'a'] = b; } memset(dp,0,sizeof(dp)); printf("%d\n",DP(0,m)); return 0;}

 

在附带一个dp的:

View Code
#include 
#include
#include
#include
#define CL(a,num) memset(a,num,sizeof(a))#define maxn 2007#define N 8using namespace std;const int inf = 99999999;int dp[maxn][maxn];char str[maxn];int addv[27],delv[27];int main(){ //freopen("din.txt","r",stdin); int n,m,i,l,j; char ch[3]; int a,b; scanf("%d%d",&n,&m); scanf("%s",str); for (i = 0; i < n; ++i) { scanf("%s%d%d",ch,&a,&b); addv[ch[0] - 'a'] = a; delv[ch[0] - 'a'] = b; } CL(dp,0); for (l = 0; l < m; ++l) { for (i = 0; i + l < m; ++i) { j = i + l; if (str[i] == str[j]) dp[i][j] = dp[i + 1][j - 1]; else dp[i][j] = min(dp[i + 1][j] + min(addv[str[i] -'a'],delv[str[i] - 'a']), dp[i][j - 1] + min(addv[str[j] -'a'],delv[str[j] - 'a'])); } } printf("%d\n",dp[0][m - 1]); return 0;}

转载于:https://www.cnblogs.com/E-star/archive/2012/08/12/2635225.html

你可能感兴趣的文章
【转】redo与undo
查看>>
解决升级系统导致的 curl: (48) An unknown option was passed in to libcurl
查看>>
Java Session 介绍;
查看>>
spoj TBATTLE 质因数分解+二分
查看>>
Django 模型层
查看>>
dedecms讲解-arc.listview.class.php分析,列表页展示
查看>>
Extjs6 经典版 combo下拉框数据的使用及动态传参
查看>>
【NodeJS】http-server.cmd
查看>>
研磨JavaScript系列(五):奇妙的对象
查看>>
面试题2
查看>>
selenium+java iframe定位
查看>>
P2P综述
查看>>
第五章 如何使用Burp Target
查看>>
Sprint阶段测试评分总结
查看>>
sqlite3经常使用命令&amp;语法
查看>>
linux下编译openjdk8
查看>>
【python】--迭代器生成器装饰器
查看>>
Pow(x, n)
查看>>
安卓当中的线程和每秒刷一次
查看>>
每日一库:Modernizr.js,es5-shim.js,es5-safe.js
查看>>