代码随想录训练营第35天 || 01背包问题 416. 分割等和子集

01背包问题

就是将一些有价值的物品(只能放一次),放入有限容量的背包里,怎么放价值最大。

二维数组方法

动规五部曲:


1.dp数组及下标含义

dp[ i ][ j ]

dp数组表示当前背包容量,当前可放入物品下,最大的背包价值,下标的含义:i是物品,j是背包的递推容量(为什么叫递推容量,因为背包的容量是一点一点在扩大,来推出最终背包的总容量的最大价值),当然也可以颠倒。

2.递推公式:

dp[ i ][ j ] = max( dp[ i-1 ][ j ] ,dp[ i-1 ][j-weight[ i ](表示i物品的重量)+value[i] )

3. dp数组如何初始化

把最左边一列和最上面一行初始化,因为其他的数组元素都是由上一个元素和左上的元素推出来的

左边一列为0,因为此时背包容量为0,上面一列,只能放物品0,要么是0,要么最大就是物品0的价值

4.确定遍历顺序:

遍历顺序:任意顺序都可

5.例举

总结:为什么求一个总背包容量的最大价值要拆分成二维数组,因为最终结果是由小背包容量推出来的

滚动数组方法:

1.dp数组及下标含义

dp [ j ] : j 是为了延续二维数组的方法j的含义,j是背包的容量

2.递推公式:

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

与二维数组不同的是,数组是重复利用的,所有当前数组如果不修改就等效为二维数组时上一层的数组

3. dp数组如何初始化

4.确定遍历顺序:

遍历顺序只能先遍历物品,再遍历背包容量,并且遍历背包容量只能倒序(倒序遍历是为了保证物品i只被放入一次)

5.例举

416. 分割等和子集

思路:

01背包的应用:因为要分割成两个等和的子集,所以把一半的和想象成背包,只要在数组中找到能够装满这个背包的子集就行

代码:

class Solution {
public:
    bool canPartition(vector& nums) {
        int sum = 0;
        vector dp(10001,0);//dp数组的初始化
        for(int i = 0;i= nums[i];j--)//为什么从target开始遍历,因为target是背包最大容量
            {
                dp[j] =max(dp[j] , dp[j-nums[i]]+nums[i]);//max中的dp[j]是不放入dp当前i物品也就是num[i],dp[j-nums[i]]+nums[i]是放入nums[i]
            }
        }
        if (dp[target] == target)return true;
        return false;
    }
};

遇到的问题:

1.对于总和的一半想象成背包总重量的背包问题,并且每个数字本身代表价值和重量

2. for(int j = target;j >= nums[i];j--)//为什么从target开始遍历,因为target是背包最大容量

你可能感兴趣的:(算法)