day 42 01背包

文章介绍了使用动态规划解决01背包问题,包括二维数组和一维滚动数组的实现方式,以及如何找到能分割成两个元素和相等的子集。动态规划的核心是状态转移方程和初始化策略,通过递推公式计算最大价值。最后,文章给出了解决分割等和子集问题的代码示例。
摘要由CSDN通过智能技术生成

01背包裸题
有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。
每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

二维数组

  1. dp含义:
    dp[ i ][ j ] 表示从下标为 [ 0 - i ]的物品里任意取,放进容量为 j 的背包,价值总和最大是多少。

  2. 递推公式
    在分析第 i 个物品 dp[ i ][ j ] 能否放到背包j里时,有以下三种情况
    (1)w[ i ] > 背包总重量 不放 dp[ i ][ j ] = dp[ i - 1 ][ j ]
    (2)不放 dp[ i ][ j ] = dp[ i - 1 ][ j ]
    (3)放进去 dp[ i ][ j ] = dp[ i - 1 ][ j - w[ i ] ] + v[ i ]
    则 dp[ i ][ j ] = max (dp[ i - 1 ][ j - w[ i ] ] + v[ i ], dp[ i - 1 ][ j ]

  3. 初始化
    如果物品下标从0开始
    for (int j = weight[0]; j <= bagweight; j++) { dp[0][j] = value[0];}
    如果物品下标从1开始 , 直接初始化为0 就行

  4. 顺序 由递推公式可见,当前值取决于自己左上角的值,那么先遍历重量,再遍历物品 和 先遍历物品再遍历重量是一样的

一维滚动数组
原理:当前层的状态只与上一层有关系,所以把上一层的数字拷贝下来,到当前层进行计算,用新的值进行覆盖,把二维数组压缩为一维

  1. dp含义:
    dp[ j ] 容量为j的背包能装的最大价值

  2. 递推公式
    dp[ j ] = max(dp[ j ], dp[ j - w [ i ] ] + v[ i ])
    因为该层数据使上一层拷贝下来的所以原本的 dp[ j ] == dp[ i - 1 ][ j ]

    在分析第 i 个物品 dp[ i ][ j ] 能否放到背包j里时,有以下三种情况
    (1)w[ i ] > 背包总重量 不放 dp[ i ][ j ] = dp[ i - 1 ][ j ]
    (2)不放 dp[ i ][ j ] = dp[ i - 1 ][ j ]
    (3)放进去 dp[ i ][ j ] = dp[ i - 1 ][ j - w[ i ] ] + v[ i ]
    则 dp[ i ][ j ] = max (dp[ i - 1 ][ j - w[ i ] ] + v[ i ], dp[ i - 1 ][ j ]

  3. 初始化
    dp[ 0 ] = 0 非零下标,由于背包是正数背包,并且更新时求max 那么 初始化为正数的最小值 0

  4. 顺序 正序遍历物体,逆序遍历背包
    列表后面的值需要通过与上一层遍历得到的前面的值比较确定
    如果不采用倒序遍历,遍历后一个状态时,要用到前面某个状态的值dp[j-w[i]],而前面的状态值通过正序在本轮遍历已经被覆盖了,而计算后一个状态的值时需要的是覆盖前的值

在这里插入图片描述
416. 分割等和子集

题目:
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
分析:
那么只要找到集合里能够出现 sum / 2 的子集总和,就算是可以分割成两个相同元素和子集了。
背包容量为 sum / 2 物品为数组nums 重量为 nums[ i ] 价值为 nums[ i ]
dp[sum/2] == sum/2 表示能装满
一维背包 逆序遍历 dp[j] = max(dp[j], dp[j-nums[i]] + nums[i]);

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for(int i=0; i<nums.size(); i++){
            sum += nums[i];
        }
        if(sum%2 == 1) return false;
        int c = sum/2;
        vector<int>dp(c + 1, 0);
        for(int i=0; i<nums.size(); i++){
            for(int j=c; j>=nums[i]; j--){
                dp[j] = max(dp[j], dp[j-nums[i]] + nums[i]);
            }
        }
        if(dp[c] == c) return true;
        return false;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值