记录结果再利用的“动态规划”

记录结果再利用的“动态规划”

记忆化搜索

书中以背包为例子,和树状dp 不同,是种一维dp.

如果不记忆化,复杂度为O(n^2)
只不过,这种方法的搜索深度是n,而且每一层的搜索都需要两次分支,最坏就需要O(2”)的时间,
当n比较大时就没办法解了。所以要怎么办才好呢?为了优化之前的算法,我们看一下针对样例
输入的情形下rec递归调用的情况。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dz4iuIwJ-1606893759569)(C:\Users\Gumption\AppData\Roaming\Typora\typora-user-images\1605673215226.png)]

如图所示,rec以(3,2)为参数调用了两次。如果参数相同,返回的结果也应该相同,于是第二次调
用时已经知道了结果却白白浪费了计算时间。让我们在这里把第一次计算时的结果记录下来,省
略掉第二次以后的重复计算试试看。

记忆化搜索后就仅需O(nW)的复杂度(注*:n是物品个数,W是背包状态)

讲解了记忆化搜索的代码*(见图一)和不利于记忆化搜索的代码*(见码二)

码一:
int dp[MAX_N +1][MAX_W + 1];//记忆化数组
int rec(int i, int j){
if (dp[i][j] >= 0){
//已经计算过的话直接使用之前的结果
return
dp[i][j];
int res;
if (i == n) {
	res = 0;else if (j<w[i]){
	res = rec(i + 1, j) ;else {
	res = max(rec(i + 1, j), rec(i +1,j-w[i]) +v[i]);
	}
//将结果记录在数组中
return dp[i][j] = res;

void solve() {
    //用-1表示尚未计算过,初始化整个数组
    memset (dp, -1, sizeof (dp)) ;
    printf ("%d\n", rec (0, W) ) ;
}

码二:
穷竭搜索的写法
如果对记忆化搜索还不是很熟练的话,可能会把前面的搜索写成下面这样
// 目前选择的物品价值总和是sum,从第1个物品之后的物品中挑选重量总和小于j的物品
int rec(int i, int j, int sum) {
int res;
if (i ==n) {
//已经没有剩余物品了
res = sum;else if (j<w[i]){
//无法挑选这个物品
res = rec(i + 1, j, sum) ;else {
//挑选和不挑选的两种情况都尝试一下
res = max(rec(i + 1, j, sum), rec(i + 1, j - w[i], sum +v[i]));
return res;
在需要剪枝的情况下,可能会像这样把各种参数都写在函数上,但是在这种情况下会让记忆
化搜索难以实现,需要注意。

两者的区别就是前者是返回截止每层的最大值(每层皆返回)

数都写在函数上,但是在这种情况下会让记忆
化搜索难以实现,需要注意。


两者的区别就是前者是返回截止每层的最大值(每层皆返回)

后者是到最后才返回,这样的动态规划不利于每层都记录。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值