背包问题
题目链接 题目页面 (kamacoder.com)
对于固定容量的背包,装不同重量、不同价值的东西的动态规划算法,定义dp数组,其中dp[i]为容量为i的背包所能容纳东西的最大价值,同时遍历i和j,i代表着所装物体的编号、j代表着背包容量大小,此时,递归函数为:dp[j]=max(dp[j-1],dp[j-weight[i]]+value[i]) ,同时为了防止小重量物件多次选取,背包容量j从大到小遍历:
for (int i = 0; i < M; ++i) {
// 内层循环从 N 空间逐渐减少到当前研究材料所占空间
for (int j = N; j >= costs[i]; --j) {
// 考虑当前研究材料选择和不选择的情况,选择最大值
dp[j] = max(dp[j], dp[j - costs[i]] + values[i]);
}
}
416. 分割等和子集
作为一维背包问题的应用,本题相对抽象,将一个数组中的数分割成相等的两部分,可以看作在数组中找出几个数的组合,使其和为数组总和的一半,同样可以看作,往容量为总和一半的背包中塞入数组的最大值是否为总和一半,也就是是否有和等同与综合一半的数组组合。此时的递归函数可以写成一维背包问题:dp[j]=max(dp[j],dp[j-nums[i]]+nums[i]),其中dp[j-nums[i]]是作为当前背包总和减去要装入背包的值所剩下的体积所能容纳的历史最大盛放量,后面的nums[i]则是装入当前数字所带来的盛放量,对于所要带上的多个数字,将每个数字从头到尾遍历一遍,在每一个数字遍历时,将背包的容量从大到小遍历一遍:
for(int i=0;i<nums.size();i++){
for(int j=target;j>=nums[i];j--){//大于等于nums[i]
dp[j]=max(dp[j],dp[j-nums[i]]+nums[i]);
}
}
同时背包容量在大于当前所要盛放物体的量时遍历,小于时不再遍历(无效果,不可能再塞入)
初始化时则是将数组置0,
vector<int>dp(10000,0);
10000是总和所能达到的最大值,背包容量是从所能达到的最大值开始遍历。
最后则是看数组总和一半容积的容器所能装载的物品能否达到总和一半:
if(dp[target]==target)