赞
踩
【声明】以下内容参考了代码随想录,不用作商业用途~
先来看一个场景:有N件物品,背包最大的重量为W,第i件物品的重量为weight[i],得到的价值为value[i],每件物品只用一次(即不能重复放进背包),求怎么装,背包内物体的价值总和是最大的。
像上面这样的问题,其实就是经典的01背包问题,那01背包问题
【解法分析】
这里我们需要构造一个二维数组,二维数组的数据结构如下所示:
这个数组乍一看还是有点云里雾里,其实这里就是用一个二维数组去遍历所有的情况,每个空格表示当前情况下的最大的价值总和,比如dp[i][j]
表示当前背包的最大容量为j,里面可放的物品为0-i
;
那么接下来我们来推导dp[i][j]
,我们一般都希望通过上一个状态去推导现在的状态,但是在二维数组中上一个状态有两个方向,比如dp[i-1][j]
和dp[i-1][j-weight]
,其实写到这里很多人都无法理解为啥突然就是这样子的(尤其逻辑性很强的同学(狗头)),下面具体分析一下,为什么是这样,我的推荐是先记住,然后通过下面的分析知道为什么就可以,自己从0到1推真的很难。
dp[i-1][j]
推出,根据上面的描述,dp[i-1][j]
表示背包容量为i,里面不放物品i的最大价值,说明此时背包容量利用已经最大化了,加不了其他的物品了,所以dp[i][j]
就是dp[i-1][j]
;dp[i-1][j-weight]
推出,此时背包容量已经利用最大化,那么dp[i][j]
背包容量多了一个物品i的重量,可以放下物品i,所以此时物品的最大价值为dp[i-1][j-weight]+value[i]
;因此,我们可以得到递推公式:
dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight]+value[i]
接下来,我们需要初始化dp数组,如果背包容量为0,那么背包里面价值肯定也是为0;如下所示:
然后就是遍历,具体细节还是推荐大家去看代码随想录的解析。
下面是一个使用01背包的例题:
只有确定了如下四点,才能把01背包问题套到本题上来。
以上分析完,我们就可以套用01背包,来解决这个问题了。
/** * @param {number[]} nums * @return {boolean} */ var canPartition = function(nums) { var sum=0; var dp=Array(20001).fill(0); for(var i=0;i<nums.length;i++){ sum=sum+nums[i]; } if(sum%2==1)return false; var target=sum/2; for(var i=0;i<nums.length;i++){ for(var 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 false; };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。