动态规划之01背包

动态规划之01背包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
在这里插入图片描述

  1. 确定dp数组以及下标的含义
    对于背包问题,有⼀种写法, 是使⽤⼆维数组,即dp[i][j] 表示从下标为[0-i]的物品⾥任意取,放进容量为j的背包,价值总和最⼤是多少

  2. 确定递推公式
    再回顾⼀下dp[i][j]的含义:从下标为[0-i]的物品⾥任意取,放进容量为j的背包,价值总和最⼤是多少。
    那么可以有两个⽅向推出来dp[i][j],
    由dp[i - 1][j]推出,即背包容量为j,⾥⾯不放物品i的最⼤价值,此时dp[i][j]就是dp[i - 1][j]
    由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最
    ⼤价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最⼤价值
    所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])

  3. dp数组如何初始化
    关于初始化,⼀定要和dp数组的定义吻合,否则到递推公式的时候就会越来越乱。
    ⾸先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],⽆论是选取哪些物品

package ywy;

/**
 * @author 是狸猫啊!
 * @version 1.0
 */
public class ywy {
    public static void main(String[] args) {
        int[] wight = {1, 3, 4};
        int[] value = {15, 20, 30};
        int bagWeight = 4;
        int[][] dp = new int[wight.length + 1][bagWeight + 1];
        //二维数组的初始化
        //我自己在做这个题的时候,有点不太理解这里为什么要进行的是倒序遍历
        //其实这有一个好处,就是可以dp[0][0]这个为1  其余的值是15  只对第一行进行初始化,
        //为什么不对第一列进行初始化啊?
        //那是因为j = 0 的时候是对第一列的元素进行的初始化,代表的是背包的容量为0的时候,后面会填充进去的.
        for (int j = bagWeight; j >= wight[0]; j--) {
            dp[0][j] = dp[0][j - wight[0]] + value[0];
        }

        for (int i = 0; i < dp.length; i++) {
            for (int j = 0; j < dp[i].length; j++) {
                System.out.print(dp[i][j]);
            }
            System.out.println();
        }

        //进行背包的填充
        for (int i = 1; i < wight.length; i++) {
            for (int j = 0; j <= bagWeight; j++) {
                if (j < wight[i]) {
                    dp[i][j] = dp[i - 1][j];
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j],dp[i -1][j - wight[i]] + value[i]);
                }
            }
        }
        System.out.println("======================================");
        for (int[] ints :dp) {
            for (int i :ints) {
                System.out.print(i);
            }
            System.out.println();
        }

    }
}

一维dp数组(对背包进行一个压缩)

  1. 在⼀维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最⼤为dp[j]
  2. dp[j - weight[j]]我觉得这个东西更多是一个现在背包容量的问题,j表示的背包的容量,你把前面的那个数一减,加上现在背包的容量

重点解读:

为什么不能够进行对j不能够进行正序遍历了

  • 如果正序遍历
    dp[1] = dp[1 - weight[0]] + value[0] = 15
    dp[2] = dp[2 - weight[0]] + value[0] = 30 此时dp[2]就已经是30了,意味着物品0,被放⼊了两次,所以不能正序遍历。
  • 那么问题⼜来了,为什么⼆维dp数组历的时候不⽤倒叙呢?
    因为对于⼆维dp,dp[i][j]都是通过上⼀层即dp[i - 1][j]计算⽽来,本层的dp[i][j]并不会被覆盖!
    (如何这⾥读不懂,⼤家就要动⼿试⼀试了,空想还是不靠谱的,实践出真知!)
    再来看看两个嵌套for循环的顺序,代码中是先遍历物品嵌套遍历背包容量,那可不可以先遍历背包容量
    嵌套遍历物品呢?
    public static void text(){
        int[] wight = {1, 3, 4};
        int[] value = {15, 20, 30};
        int bagWeight = 4;
        //进行dp数组的初始化
        int[] dp = new int[bagWeight + 1];

        for (int i = 0; i < wight.length; i++) {
            for (int j = dp.length; j > 0; j++) {
                dp[j] = dp[j - wight[i]] + value[i];
            }
        }

        System.out.println(dp[dp[dp.length - 1]]);
    }

] + value[i];
}
}

    System.out.println(dp[dp[dp.length - 1]]);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值