【Day42】代码随想录之动态规划0-1背包_416. 分割等和子集

2024-02-16 19:12

本文主要是介绍【Day42】代码随想录之动态规划0-1背包_416. 分割等和子集,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

      • 动态规划理论基础
        • 动规五部曲:
        • 出现结果不正确:
      • 416. 分割等和子集

动态规划理论基础

动规五部曲:
  1. 确定dp数组 下标及dp[i] 的含义。
  2. 递推公式:比如斐波那契数列 dp[i] = dp[i-1] + dp[i-2]。
  3. 初始化dp数组。
  4. 确定遍历顺序:从前到后or其他。
  5. 推导dp数组。
出现结果不正确:
  1. 打印dp日志和自己想的一样:递推公式、初始化或者遍历顺序出错。
  2. 打印dp日志和自己想的不一样:代码实现细节出现问题。

416. 分割等和子集

参考文档:代码随想录

题目:

给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200

  • 示例 1:
    输入: [1, 5, 11, 5]
    输出: true
    解释: 数组可以分割成 [1, 5, 5] 和 [11].
  • 示例 2:
    输入: [1, 2, 3, 5]
    输出: false
    解释: 数组不能分割成两个元素和相等的子集.
  • 提示:
    1 <= nums.length <= 200
    1 <= nums[i] <= 100

分析:
问题抽象

dp五部曲:

  1. dp[j]含义:背包重量为i时候可以装最大价值数。
  2. 递推公式:dp[j] = max(dp[j], dp[j-nums[i]] + nums[i]);
  3. 初始化:vector<int> dp(total+1, 0); 不能影响dp[j]的更新,设为最小自然数0。
  4. 遍历顺序:双重for循环,先物品再背包,内层for循环的循环体 倒序 更新dp,适应滚动数组,不影响之前的更新,正序因为只有一个一维数组,所以会影响后面的更新。
  5. 打印:
    输入: [1, 5, 11, 5]
    dp更新:
    下标值:0,1,2,3,4,5,6,7,8,9,10,11
    初始化:0,0,0,0,0,0,0,0,0,0,0,0
    i = 0 :0,1,1,1,1,1,1,1,1,1,1,1
    i = 1 :0,1,1,1,1,5,6,6,6,6,6,6
    i = 2 :0,1,1,1,1,5,6,6,6,6,6,11
    i = 3 :0,1,1,1,1,5,6,6,6,6,10,11
    代码:
class Solution {
public:bool canPartition(vector<int>& nums) {int total = 0;for(int i = 0; i < nums.size(); i++){total += nums[i];}if(total % 2) return false;total /= 2;// 背包的目标体积vector<int> dp(total+1, 0);for(int i = 0; i < nums.size(); i++){//物品个数0-nums.size()-1for(int j = total; j >= nums[i]; j--){//背包的体积0-totaldp[j] = max(dp[j], dp[j-nums[i]]+nums[i]); //递推公式}}if(dp[total] == total) return true;return false;}
};

二维数组实现:

  1. dp[i][j]含义:从0-i的物品中任取到重量限制为j的背包得到的最大价值数。
  2. 递推公式:dp[i][j] = max(dp[i-1][j], dp[i-1][j-nums[i]] + nums[i]);
  3. 初始化:vector<vector<int>> dp(nums.size(), vector<int>(total+1, 0)); 第一列表示背包的重量为0时的价值为0,第一行表示在物品0存在的情况下背包不同重量的价值,满足条件的初始化为物品0的价值,其他元素都需要之后从上和左上的二维数组元素值计算得出,所以初始化值任意。
  4. 遍历顺序:双重for循环,对于二维数组,先物品再背包或者先背包再物品,在当前额日伪数组求最大价值的时候上和左上元素都是存在的,所以遍历顺序任意。

先物品再背包

class Solution {
public:bool canPartition(vector<int>& nums) {int total = 0;for(int i = 0; i < nums.size(); i++){total += nums[i];}if(total % 2) return false;total /= 2;// 背包的目标体积//二维数组vector<vector<int>> dp(nums.size(), vector<int>(total+1, 0));for(int i = total; i >= nums[0]; i--) dp[0][i] = nums[0];for(int i = 1; i < nums.size(); i++){//先物品for(int j = 1; j <= total; j++){//再背包if(j < nums[i]) dp[i][j] = dp[i-1][j];else dp[i][j] = max(dp[i-1][j], dp[i-1][j-nums[i]]+nums[i]);}}if(dp[nums.size()-1][total] == total) return true;return false;}
};

先背包再物品

class Solution {
public:bool canPartition(vector<int>& nums) {int total = 0;for(int i = 0; i < nums.size(); i++){total += nums[i];}if(total % 2) return false;total /= 2;// 背包的目标体积//二维数组vector<vector<int>> dp(nums.size(), vector<int>(total+1, 0));for(int i = total; i >= nums[0]; i--) dp[0][i] = nums[0];for(int j = 1; j <= total; j++){//先背包for(int i = 1; i < nums.size(); i++){//再物品if(j < nums[i]) dp[i][j] = dp[i-1][j];else dp[i][j] = max(dp[i-1][j], dp[i-1][j-nums[i]]+nums[i]);}}if(dp[nums.size()-1][total] == total) return true;return false;}
};

这篇关于【Day42】代码随想录之动态规划0-1背包_416. 分割等和子集的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/715442

相关文章

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

poj2576(二维背包)

题意:n个人分成两组,两组人数只差小于1 , 并且体重只差最小 对于人数要求恰好装满,对于体重要求尽量多,一开始没做出来,看了下解题,按照自己的感觉写,然后a了 状态转移方程:dp[i][j] = max(dp[i][j],dp[i-1][j-c[k]]+c[k]);其中i表示人数,j表示背包容量,k表示输入的体重的 代码如下: #include<iostream>#include<

hdu2159(二维背包)

这是我的第一道二维背包题,没想到自己一下子就A了,但是代码写的比较乱,下面的代码是我有重新修改的 状态转移:dp[i][j] = max(dp[i][j], dp[i-1][j-c[z]]+v[z]); 其中dp[i][j]表示,打了i个怪物,消耗j的耐力值,所得到的最大经验值 代码如下: #include<iostream>#include<algorithm>#include<

csu(背包的变形题)

题目链接 这是一道背包的变形题目。好题呀 题意:给n个怪物,m个人,每个人的魔法消耗和魔法伤害不同,求打死所有怪物所需的魔法 #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>//#include<u>#include<map

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n