01背包——滚动数组动态规划优化

40 篇文章 1 订阅
21 篇文章 1 订阅

        在上篇讲述了01背包基础问题,但是代码思想任然存在可优化地方,比如我们可以从递推公式可以看出来:

原递推公式

        当前承重量的背包最大容纳价值 = max(腾出新物品空位后的背包承重量最大价值 + 新物品的价值,不加入新物品的最大价值);

        dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

原递推思路

        定义一个二维数组,每一列为从0-max解放的背包重量,每一行表示新解放的物品

当只能放物品1时,背包容量从0-max,每个容量对应的最大价值就为
              0  1   2   3   4
        15  0 15 15 15 15
        20
        30

当解放物品2,那么背包容量从0-max,每个容量对应的最大价值就为

              0  1   2   3   4
        15  0 15 15 15 15
        20  0 15 15 20 35
        30  

当解放物品2,那么背包容量从0-max,每个容量对应的最大价值就为

              0  1   2   3   4
        15  0 15 15 15 15
        20  0 15 15 20 35
        30  0 15 15 20 35

问题

        递推公式只用到了 用于记录结果的本层数组,以及已经记录了最大值的上层数组,而前面所有的已经记录的最大值在经历完一层递推之后就毫无作用,每一层的递推都是根据上一层结果从左向右完成。完成后上层数据便失去了意义。

解决方案

        我们采用一维数组去解决这样的问题,每次使用该数组时,该数组记录的是上一层的结果。我们观察此前的推导数组可以发现,每一个数组元素的推导,都是由该元素正上方元素,与左上方一行某个元素+value值比较。所以每个元素的推导需要的值我们可以看做一个L型

               值1        值2        值3        值4

                                         目标            

        这个L型就是加粗的L型

        要想知道目标最贵摆放法,就需要用值3 与 减去目标重量后的最大值 + 目标的值 做比较。现在我们使用一维数组,如果还是从左向右遍历,那么就可能出错。

前:

                原值1        原值2        原值3        原值4

                                 目标

后:

                原值1        新值2       原值3        原值4

                                                 目标

        前者正常赋值即可,但是到后者,我们发现,由于前者的更新,给后者的计算条件照成了偏差,所以我们得从右向左遍历,这样右面新更新的值就无法影响前者的更新。

滚动数组递推公式

        dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);

解题代码:

public class Bag02 {
    public static void main(String[] args) {
        int[] weight = new int[]{1, 2, 3, 4};
        int[] value = new int[]{15, 40,20, 30};

        int i = maxValue(weight, value, 5);
        System.out.println(i);
    }

    public static int maxValue(int[] weight, int[] value, int bagWeight) {
        //定义一个一维数组
        int[] realValue = new int[bagWeight + 1];

        //初始化滚动数组
        for (int i = realValue.length - 1; i >= 0; i--) {
            if (i >= weight[0]){
                realValue[i] = value[0];
            }
        }

        //当重量为1时,首先给一维数组赋值
        for (int i = 1; i < weight.length; i++) {
            for (int j = realValue.length - 1; j >= 0; j--) {
                if (weight[i] <= j) {
                    realValue[j] = Math.max(realValue[j], realValue[j - weight[i]] + value[i]);
                } else {
                    continue;
                }
            }
        }

        return realValue[realValue.length - 1];
    }
}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aristocrat l

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值