首页 > 其他分享 >从理论到实践:01背包问题在分割等和子集中的应用(力扣416)

从理论到实践:01背包问题在分割等和子集中的应用(力扣416)

时间:2024-04-10 21:02:13浏览次数:19  
标签:01 target nums 元素 力扣 416 背包 数组 dp


文章目录


昨天的文章(传送门)中,我们从理论对01背包问题进行了基础详细的讲解,从二维数组到一维数组进行优化,今天我们用实际题目来运用一下01背包问题的动态规划,要使用01背包问题中的一维dp数组解题,如果对这个不清楚的话,可以先观看上期视频了解01背包一维dp数组的使用方法,相信结合上期文章再观看本文会理解的更加透彻

在这里插入图片描述

题目

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

示例 2:

输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。



题解

一、思路

看到这个题目要求,要求集合中出现两个和为sum/2的子集,可以看作将nums数组里面的元素放进子集中能出现满足sum/2的情况,nums数组每个元素只能用一次,集合里的元素可以看作01背包中的物品,每个物品只能用一次,而背包体积自然就是sum/2,元素(物品)的重量和价值是相等的都为元素的数值nums[i]

可以将本题与上期01背包结合,转化得到下表:

物品重量价值
元素011
元素155
元素21111
元素355

二、解题方法

动规五部曲

  1. 确定dp数组及下标i的含义:dp[j]表示 子集总容量(所能装的总重量)是j,放进元素后,子集中的最大重量为dp[j]。如示例1中:target为11,dp[11]表示子集的和为11,放进nums数组中的元素[1,5,5][11]后,子集的最大重量为dp[11],那么如果背包容量为target, dp[target]就是装满 背包之后的重量,所以 当 dp[target] == target 的时候,背包就装满了。

  2. 确定递推公式:由01背包问题的一维dp数组递推公式与nums数组里的元素的重量和价值相等得出dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);

// 标准01背包问题的一维dp数组:
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

//分割等和子集的一维dp数组
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
  1. dp数组如何初始化:dp[0]表示子集和为0,所以dp[0]=0,其它非零下标的dp数组就可以像01背包问题一样取0即可,保证会被递推过程中的最大值覆盖掉
int[] dp = new int[target+1];
  1. 确定遍历顺序:同样是先从前到后遍历物品,再倒序遍历背包容量,只是在这里,物品是nums数组里的每个元素nums[i],最大的背包容量则是子集要求的sum/2,当内层的for循环背包总容量小于元素的值的话,说明背包已经装不下元素了,此时就看子集是否刚好装满元素,如果已经满足等和子集了,那么提前就返回true
for(int i=0;i<nums.length;i++){
    for(int j=target;j>=nums[i];j--){
        dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]);
    }
    // 剪枝操作
    if(dp[target] == target){
        return true;
    }
}
  1. 举例推导dp数组:dp[j]的数值一定是小于等于j的,例如在示例一中dp[8]=7,无论怎么样放元素都不会有子集和为8的情况出现,如果dp[j] == j 说明,集合中的元素总和正好可以凑成子集总和j,最后dp[11] = 11说明可以将这个数组分割成两个子集,使得两个子集的元素和相等
物品重量价值
元素011
元素155
元素21111
元素355

image.png

三、Code

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for(int num : nums) {
            sum += num;
        }

        // 剪枝:和若为奇数无法进行分割等和
        if(sum % 2 != 0) {
            return false;
        }
        // 背包的体积为和的一半
        int target = sum / 2;
        int[] dp = new int[target+1];
        // 先遍历物品,再倒序遍历背包容量
        for(int i=0;i<nums.length;i++){
            for(int j=target;j>=nums[i];j--){
                dp[j] = Math.max(dp[j],dp[j-nums[i]]+nums[i]);
            }
            // 元素的重量与价值相等
            if(dp[target] == target){
                return true;
            }
        }
        return dp[target] == target;
    }
}


总结

通过这篇博客,读者可以清晰地了解如何结合01背包问题在实际问题中的使用,本题的关键在于想到是否可以从输入数组中挑选出一些正整数,使得这些数的和 等于 整个数组元素的和的一半,再抽象成一个01背包问题。
希望本文能够帮助读者更好地理解和应用动态规划算法在01背包问题中的使用,如果有任何疑问或者建议,欢迎留言讨论

标签:01,target,nums,元素,力扣,416,背包,数组,dp
From: https://blog.csdn.net/Huahua_1223/article/details/137609618

相关文章

  • MHY1001. [崩三]椰子树题解
    #include<bits/stdc++.h>usingnamespacestd;constintN=1010,M=20010;intq[M];//s的最大值为20000,v的最小值为1,所以队列里面最多是会有200010个元素的intn,m;intf[M],g[M];intmain(){cin>>n>>m;for(inti=1;i<=n;++i){......
  • L3-011 直捣黄龙
    dijkstra+判断。#include<bits/stdc++.h>usingnamespacestd;constintinf=0x3f3f3f3f;intedges[210][210],visited[210];intcnt[210],enemy[210],pre[210],path[210];//累计城镇累计歼敌前驱结点多少条路intdist[210];//dist[i]从起点到达i最短的距离map<stri......
  • P5610 [Ynoi2013] 大学
    [Ynoi2013]大学-洛谷傻逼卡常题发现自己基础数据结构用的还不是很熟练,并没有想到一开始的\(set\)做法,更不用提后面的并查集优化了首先每个数最多被进行\(O(\logA)\)次有效除法,如果我们找到区间中哪些数要被除后直接暴力用树状数组单点修改,可以做到\(O(n\logn......
  • 运维系列(亲测有效):利用 PHPStuday 2018 集成化工具对Apache进行站点域名管理
    利用PHPStuday2018集成化工具对Apache进行站点域名管理利用PHPStuday2018集成化工具对Apache进行站点域名管理利用PHPStuday2018集成化工具对Apache进行站点域名管理第一步:第二步:第三步:第四步:第五步:利用PHPStuday2018集成化工具对Apache进行站点域......
  • 0001命令式和声明式
    命令式命令式框架的一大特点就是关注过程就如下面的代码,自然语言描述能够与代码产生一一对应的关系,代码本身描述的是"做事的过程",这符合我们的逻辑直觉constdiv=document.querySelector('#app')//获取divdiv.innerText='helloworld'/......
  • [SDOI2017] 硬币游戏
    [SDOI2017]硬币游戏还是因为感觉网上的写的不够清晰,所以来写一篇用\(P(i)\)表示第\(i\)个同学胜利的概率,\(s_i\)表示第\(i\)个同学猜的序列可以发现,第\(i\)个同学胜利当且仅当当前硬币序列\(T\)的后\(m\)位刚好为\(s_i\),且\(T\)除了最后\(m\)位出现过\(s_i\),其他任何位置都......
  • 01 Php学习:导学篇
    Php是什么?PHP是服务器端脚本语言。PHP(HypertextPreprocessor)是一种通用开源脚本语言,主要用于服务器端开发。PHP脚本在服务器端执行,生成动态网页内容或执行服务器端任务。PHP可以嵌入到HTML中,也可以与各种数据库结合使用,常用于开发Web应用程序。PHP文件可包含文本、HT......
  • P3891 [GDOI2014] 采集资源 题解
    题面。看到大家都是两个动态规划的写法,来给大家讲一下只用一次动态规划的写法。思路设\(f_{i,j}\)表示工作效率为\(i\),获取\(j\)点资源所需的最短时间,不以苦工设状态是因为苦工会因为后面购买而改变,不太现实。\(tme\)表示答案,即到达\(t\)点资源所需的最短时间。从\(0......
  • P8661 [蓝桥杯 2018 省 B] 日志统计 题解
    好久没写题解了,水一篇。这里主要想讲的是不同的处理方法,在阅读本篇题解前请确保读完题。详解一,排序这很好理解,题目要求将热帖从小到大输出,同时题目中还有相对的时间这一概念,因此将输入的\(id\)与\(ts\)按照优先\(id\)其次\(ts\)的排序方式从小到大,排序,这样输出时就没......
  • Java代码(01)
    1.回文数判断(核心:如何把一个数倒过来)2.用减法实现商和余数3.求质数:4.可以进行强转5.数组作为返回值,函数名前面的int要加[]6.将一个数组中from到to的数组值复制到另一个数组中7.判断101到200之间有多少个素数并输出个数8.生成验证码9.打分1......