第九章 动态规划part04(● 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 ● 416. 分割等和子集 )

本文详细介绍了01背包问题的动态规划解决方案,包括递推公式、初始化方法,以及滚动数组在解决背包问题中的应用。同时提及了如何处理416.分割等和子集问题,通过实例演示了动态规划的实现过程。
摘要由CSDN通过智能技术生成

学习目标:

● 01背包问题,你该了解这些!
● 01背包问题,你该了解这些! 滚动数组
● 416. 分割等和子集


学习内容:● 01背包问题,你该了解这些!

https://programmercarl.com/%E8%83%8C%E5%8C%85%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8001%E8%83%8C%E5%8C%85-1.html
视频讲解:https://www.bilibili.com/video/BV1cg411g7Y6
在这里插入图片描述
1.确定dp数组以及下标的含义
i是物品,j是背包容量。
dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
2.递推公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
3.初始化:在这里插入图片描述
4.确定遍历顺序:都可以,但是先遍历物品更好理解。

好难啊,比读不懂题更显呆
/**
     * 动态规划获得结果
     * @param weight  物品的重量
     * @param value   物品的价值
     * @param size    背包的容量
     */
function testWeightBagProblem (weight, value, size) {
	// 获取物品的数量
    const len = weight.length
    const dp = Array(len).fill().map(()=>Array(size+1).fill(0))
    // 初始化dp数组
    for(let j=weight[0];j<=size;j++){
        dp[0][j]=value[0]
    }
    for(let i=1;i<len;i++){
        for(let j=1;j<=size;j++){
            if(j<weight[i]){
            /**
                     * 当前背包的容量都没有当前物品i大的时候,是不放物品i的
                     * 那么前i-1个物品能放下的最大价值就是当前情况的最大价值
              */
                dp[i][j] = dp[i-1][j]
            }else{
             /**
                     * 当前背包的容量可以放下物品i
                     * 那么此时分两种情况:
                     *    1、不放物品i
                     *    2、放物品i
                     * 比较这两种情况下,哪种背包中物品的最大价值最大
                     */
                dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i])
            }
            
        }
    }
    return dp[len-1][size]
}
function test () {
    console.log(testWeightBagProblem([2, 2 ,3 ,1 ,5, 2], [2 ,3 ,1 ,5 ,4 ,3], 6));
}
test();

学习内容:01背包问题,你该了解这些! 滚动数组

https://programmercarl.com/%E8%83%8C%E5%8C%85%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8001%E8%83%8C%E5%8C%85-2.html
视频讲解:https://www.bilibili.com/video/BV1BU4y177kY
一维数组
1.确定dp数组的定义
在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。
2.公式dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);可以看出相对于二维dp数组的写法,就是把dp[i][j]中i的维度去掉了。
3.一维dp数组如何初始化,初始化为0
4.一维dp数组遍历顺序:背包遍历倒序遍历是为了保证物品i只被放入一次!
为什么二维dp数组遍历的时候不用倒序呢?
因为对于二维dp,dp[i][j]都是通过上一层即dp[i - 1][j]计算而来,本层的dp[i][j]并不会被覆盖!
先遍历物品嵌套遍历背包容量
那可不可以先遍历背包容量嵌套遍历物品呢?
不可以!
因为一维dp的写法,背包容量一定是要倒序遍历,如果遍历背包容量放在上一层,那么每个dp[j]就只会放入一个物品,即:背包里只放入了一个物品。
倒序遍历的原因是,本质上还是一个对二维数组的遍历,并且右下角的值依赖上一层左上角的值,因此需要保证左边的值仍然是上一层的,从右向左覆盖。

function testWeightBagProblem (weight, value, size) {
    const len = weight.length
    const dp = Array(size+1).fill(0)
    for(let i=1;i<=len;i++){
        for(let j=size;j>= wight[i - 1];j--){
           dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);       
        }
    }
    return dp[size]
}
function test () {
    console.log(testWeightBagProblem([2, 2 ,3 ,1 ,5, 2], [2 ,3 ,1 ,5 ,4 ,3], 6));
}
test();

学习内容:● 416. 分割等和子集

https://programmercarl.com/0416.%E5%88%86%E5%89%B2%E7%AD%89%E5%92%8C%E5%AD%90%E9%9B%86.html
视频讲解:https://www.bilibili.com/video/BV1rt4y1N7jE
1.确定dp数组以及下标的含义
01背包中,dp[j] 表示: 容量为j的背包,所背的物品价值最大可以为dp[j]。
套到本题,dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]。
2.递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
3.初始化:dp[0]=0
4.遍历顺序:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!

两字:不会!
var canPartition = function(nums) {
    const sum = (nums.reduce((p, v) => p + v));
    if (sum & 1) return false;
    const dp = Array(sum / 2 + 1).fill(0);
    for(let i = 0; i < nums.length; i++) {
        for(let j = sum / 2; j >= nums[i]; j--) {
            dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
            if (dp[j] === sum / 2) {
                return true;
            }
        }
    }
    return dp[sum / 2] === sum / 2;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值