《dp补卡——01背包问题》

在这里插入图片描述

目录

  • 01背包
        • [416. 分割等和子集](https://leetcode-cn.com/problems/partition-equal-subset-sum/)
        • [1049. 最后一块石头的重量 II](https://leetcode-cn.com/problems/last-stone-weight-ii/)
        • [494. 目标和](https://leetcode-cn.com/problems/target-sum/)

01背包

1、dp数组以及下标含义

dp[i][j]标识从下标为[0,1]的物品里任意取,放进容量为j的背包,价值总和最大是多少?

在这里插入图片描述

2、确定递推公式

dp[i][j]可以由两个方向推出:

1、dp[i-1][j],背包容量为j,里面不放入物品i的最大价值,此时dp[i][j] = dp[i-1][j]

2、dp[i-1][i-weight[i]]推出,背包容量为i-weight[i]的时候此时dp[i][j] = dp[i-1][j-weight[i]]+valuep[i];

所以递推公式为:

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

3、dp数组如何初始化

关于初始化,一定要和dp数组的定义吻合。

如果背包容量j为0的话,dp[i][0]无论是选取哪些物品,背包价值总和一定为0。

由递推可知i是由i-1推出来的,那么i为0时一定要初始化。

dp[0][j]存放编号为0的物品时,各个容量的背包能存放的最大价值:

for(int j = bagWeight; j >= weight[0]; j--)
{dp[0][j] = dp[0][j-weight[0]] + value[0];
}

这里需要注意,初始化是倒序遍历。

dp[0][j]表示容量为j的背包存放物品0时候的最大价值。由于每个物品只有1个,如果dp[0][j]必须为初值,正序遍历,物品0会被重复加入多次。

dp[i][j]在推导的时候一定是取价值最大的数,如果题目给的价值都是正整数,那么下标初始化为0.如果价值里面有负数,初始化为负无穷。只要保证dp数组在递推公式的过程中取最大的价值,而不是被初始值覆盖。

所以dp数组初始化如下:

vector<vector<int>> dp(weight.size() + 1,vector<int>(bagWeight + 1,0));
for(int j = bagWeight; j >= weight[0]; j--)
{dp[0][j] = dp[0][j-weight[0]] + value[0];
}

4、确定遍历顺序

有两个遍历维度:物品与背包重量,先遍历物品更好理解。

for(int i = 1; i < weight.size(); i++)	//遍历物品
{for(int j = 0; j <= bagWeight; j++) //遍历背包容量	{	if(j < weight[i]) dp[i][j] = dp[i-1][j];	//else	dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]+values[i])}
}

滚动数组优化

1、确定dp数组的定义

dp[j]:容量为j的背包,所背的物品价值可以最大为dp[j]。

2、一维dp递推公式

dp[j]可以通过dp[j-weight[i]]推导,其表示容量为j-weight[i]的背包所背的最大价值。

dp[j-weight[i]]+value[i]表示容量为j-物品i重量的背包加上物品i的价值。(即容量为j的背包放入物品i之后的价值)此时dp[j]有两个选择,一个是取自己dp[j],一个是取dp[j-weight[i]]+value[i].

所以递推公式为:

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

3、初始化

假设物品价值都是大于0的,dp数组初始化的时候都初始化为0

4、确定遍历顺序

for(int i = 0; i < weight.size(); i++)	//遍历物品
{for(int j = bagWeight; j >= weight[i]; j--)	//遍历背包容量{dp[j] = max(dp[j],dp[j-weight[i]]+value[i]);}
}

二维遍历时,背包容量从小到大,一维遍历,背包容量从大到小。

这是因为倒序遍历是为了保证物品i只被放入一次。二维dp,dp[i][j]是通过上一层dp[i-1][j]计算得到的,所以本层的dp[i][j]并不会产生覆盖。

一维01背包测试代码:

void test_one_dim_01bag()
{vector<int> weight = {1,3,4};vector<int> value = {15,20,30};int bagWeight = 4;//初始化vector<int> dp(bagWeight+1,0);for(int i = 0; i < weight[i]; i++)	//遍历物品{for(int j = bagWeight; j >= weight[i]; j--)	//遍历背包容量{dp[j] = max(dp[j],dp[j-weight[i]] + value[i]);}}cout << dp[bagWeight] << endl;
}

416. 分割等和子集

求集合里是否出现总和为sum/2的子集。

背包体积为sum/2

背包放入的商品的重量为元素的数值,价值也为元素的数值

背包如何正好被装满,说明找到了总和为sum/2的子集

背包中每个元素都是不可重复放入的。

1、确定dp数组以及下标含义

dp[j]表示容量为j的背包,所背物品价值可以最大为dp[j]。

dp[j]表示背包总容量为j,最大可以凑成j的子集总和为dp[j]。

2、确定递推公式

dp[j] = max(dp[j],dp[j-nums[i]] + nums[i]);

3、初始化

vector<int> dp(target+1,0);	//target为背包容量

4、确定遍历顺序

for(int i = 0; i < nums.size(); i++)
{for(int j = target; j >= nums[i]; j--){dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]);}
}

AC代码:

class Solution {
public:bool canPartition(vector<int>& nums) {int sum = 0;for(int num : nums){sum += num;}if(sum % 2 != 0) return false;int target = sum / 2;vector<int> dp(target+1,0);for(int i = 0; i < nums.size(); i++){for(int j = target; j >= nums[i]; j--){dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]);if(dp[j] == target) return true;}}if(dp[target] == target) return true;else return false;}
};

1049. 最后一块石头的重量 II

将石头尽量分成两堆相同重量,然后相撞。分成两堆的思路与上一题一致。

class Solution {
public:int lastStoneWeightII(vector<int>& stones) {int sum = 0;for(int stone : stones){sum += stone;}int target = sum / 2;//dp[target],容量为target的背包最多能背多重的石头vector<int> dp(target+1,0);for(int i = 0; i < stones.size(); i++){for(int j = target; j >= stones[i]; j--){dp[j] = max(dp[j],dp[j-stones[i]] + stones[i]);}}return sum - dp[target]*2;}
};

494. 目标和

所有数字可以分为两堆,一堆符号为正,一堆符号为负。
pos + neg = S 且 pos - neg = sum
所以pos = (S+sum)/2,问题转化为集合nums中找出和为pos的组合。
此时问题就转化为,装满容量为pos背包,有几种方法。
这次和之前遇到的背包问题不一样了,之前都是求容量为j的背包,最多能装多少。
本题则是装满有几种方法。其实这就是一个组合问题了。
1、确定dp数组以及下标
dp[j]表示,填满体积为j的背包,有dp[j]种方法。

2、确定递推公式
不考虑nums[i],填满容量为j-nums[i]的背包,有dp[j-nums[i]]种方法,
如果能搞到nums[i],则填满容量为j-nums[i]的背包,就有dp[j]+dp[j-nums[i]]种方法。

dp[j] += dp[j-nums[i]]

3、初始化dp数组
dp[0] = 1,装满容量为0的背包,有1种方法。其他dp[i]均设置为0,在不知道nums[i]的情况下,没有方法。

4、确定遍历顺序
nums外循环,j内循环倒序。

AC代码:

class Solution {
public:int findTargetSumWays(vector<int>& nums, int target) {int sum = 0;for(int num : nums)sum += num;//如果绝对值和比targetabs小,说明都用同一个符号也不能凑成if(sum < abs(target)) return 0;//如果不能完整的分成两组,那么说明没有方法if((target + sum) % 2 == 1) return 0;int bagWeight = (target + sum)/2;vector<int> dp(bagWeight+1,0);dp[0] = 1;for(int i = 0; i < nums.size(); i++){for(int j = bagWeight; j >= nums[i]; j--){dp[j] += dp[j-nums[i]];}}return dp[bagWeight];}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/377103.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用JavaScript往DIV动态添加内容

参考&#xff1a;http://zhidao.baidu.com/link?url6jSchyqPiEYCBoKdOmv52YHz9r7MTBms2pK1N6ptOX1kaR2eg320mlW1Sr6n36hpOeOadBxC2rWWGuhZPbms-K <div id"show"></div>要填充的数据为: 这是一个测试例子.jquery&#xff1a;$(function(){ var data …

《dp补卡——完全背包问题》

N件物品和一个最多能背重量为W的背包。第i件物品的重量为weight[i]&#xff0c;得到的价值是value[i]。每件物品都有无限个(可以放入背包多次)&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 01背包和完全背包唯一不同在于遍历顺序上。 01背包的核心代码&#xff1a…

Java中的类型转换

类型转换 (Typecasting) Typecasting is a term which is introduced in all the language similar to java. Typecasting是一个用与Java类似的所有语言引入的术语。 When we assign primitive datatype to another datatype. 当我们将原始数据类型分配给另一个数据类型时。 I…

让crash文件中的内存地址变成函数名称,

假如程序员编译了inhouse给测试。 如果在测试过程中出现奔溃现象&#xff0c;我想程序员一般会来看Device Log 也就是 crash文件 如果crash文件遇到如下的情况&#xff0c;在重要的地方看不到函数名称。我想是一件很奔溃的事情。 1 Exception Type: EXC_BAD_ACCESS (SIGSEGV)2…

《dp补卡——多重背包》

多重背包简介&#xff1a; 有N种物品和一个容量为V的背包。第i种物品最多有Mi件可用&#xff0c;每件耗费的空间为Ci&#xff0c;价值为Wi。求解将哪些物品装入背包可使得这些物品耗费的空间总和不超过背包容量&#xff0c;且价值总和最大。 将Mi件摊开&#xff0c;就是一个01背…

kafka消息确认ack_什么是确认(ACK)? ACK代表什么?

kafka消息确认ackACK&#xff1a;致谢 (ACK: Acknowledgment) An acknowledgment (ACK) is a signal that is passed among the communicating processes, computers, or devices to indicate acknowledgment, or delivery of the message, as a component of a communications…

CocoaAsyncSocket 套接字

CocoaAsyncSocket 套接字 https://github.com/robbiehanson/CocoaAsyncSocket Asynchronous socket networking library for Mac and iOS 用于iOS以及Mac的异步套接字网络库。 TCP GCDAsyncSocket and AsyncSocket are TCP/IP socket networking libraries. Here are the key…

谷歌浏览器设置缓存方法

谷歌浏览器设置缓存方法&#xff1a; 1、在桌面Google Chrome快捷方式&#xff0c;目标&#xff1a;找到 C:\Users\Splendid\AppData\Local\…\Application\chrome.exe 在这后面加上-Disk-Cache-Dir”Z:\TEMP” 注意: -Disk前面有空格&#xff0c;”Z:\TEMP” 是文件存放在Z盘T…

《dp补卡——买卖股票问题》

目录121. 买卖股票的最佳时机贪心dp思路滚动数组优化122. 买卖股票的最佳时机 II123. 买卖股票的最佳时机 III188. 买卖股票的最佳时机 IV309. 最佳买卖股票时机含冷冻期714. 买卖股票的最佳时机含手续费121. 买卖股票的最佳时机 贪心 取最左最小值&#xff0c;取最右最大值&…

oo0ooo0ooo0oo_OoO的完整形式是什么?

oo0ooo0ooo0ooOoO&#xff1a;外出 (OoO: Out of Office) OoO is an abbreviation of "Out of Office". OoO是“不在办公室”的缩写。 It is an expression, which is commonly used in the Gmail platform. It is written in the body or the subject of the email…

SP2010开发和VS2010专家食谱--第三章节--高级工作流(2)--为沙盒解决方案创建自定义活动...

尽管沙河解决方案功能有限&#xff0c;你仍然可以开发自定义活动&#xff0c;在SharePoint Designer中使用而不用改变web.config或添加.ACTION文件到根文件夹。 转载于:https://www.cnblogs.com/crazygolf/p/3856795.html

sql where 1=1和 0=1 的作用

where 11; 这个条件始终为True&#xff0c;在不定数量查询条件情况下&#xff0c;11可以很方便的规范语句。 一、不用where 11 在多条件查询中的困扰 举个例子&#xff0c;如果您做查询页面&#xff0c;并且&#xff0c;可查询的选项有多个&#xff0c;同时&#xff0c;还让用户…

j@2ff4f00f_J4F的完整形式是什么?

j2ff4f00fJ4F&#xff1a;只是为了好玩 (J4F: Just For Fun) J4F is an abbreviation of "Just For Fun". J4F是“ Just For Fun”的缩写 。 It is an expression, which is commonly used in messaging or chatting on social media networking sites like Faceboo…

《dp补卡——子序列问题》

目录300. 最长递增子序列674. 最长连续递增序列718. 最长重复子数组1143. 最长公共子序列53. 最大子序和392. 判断子序列115. 不同的子序列583. 两个字符串的删除操作72. 编辑距离647. 回文子串 &#xff08;与 5.最长回文子串思路差不多&#xff09;516. 最长回文子序列300. 最…

[LeetCode] Maximal Rectangle

Given a 2D binary matrix filled with 0s and 1s, find the largest rectangle containing all ones and return its area. 在做 Largest Rectangle in Histogram的时候有人说可以用在这题&#xff0c;看了一下还真是&#xff0c;以每行为x轴&#xff0c;每列往上累计的连续的…

什么是alpha测试_什么是ALPHA?

什么是alpha测试Α (ALPHA) Alpha is the first and foremost letter of the Greek alphabet. In the classification of Greek numerals or numbers, it constitutes a value of 1. Alpha是希腊字母的第一个也是最重要的字母 。 在希腊数字或希腊数字的分类中&#xff0c;它的…

《leetcode : 647. 回文子串 思考分析双指针解法》

647. 回文子串 如何确定是回文串&#xff1a; 找中心然后往两边扩散&#xff0c;判断是否对称即可。 在遍历中心点的时候&#xff0c;注意中心点可以是一个元素也可以是两个元素。 class Solution { public:int cal_two_extend(const string& s,int i,int j,int n){int re…

天草初级班(3)

算术运算指令算术运算指令是反映CPU计算能力的一组指令&#xff0c;也是编程时经常使用的一组指令。它包括&#xff1a;加、减、乘、除及其相关的辅助指令。 该组指令的操作数可以是8位、16位和32位(80386)。当存储单元是该类指令的操作数时&#xff0c;该操作数的寻址方式可以…

4.3.3版本之引擎bug

bug描述&#xff1a;   IOS设备上&#xff0c;当使用WWW www WWW.LoadFromCacheOrDownload(url, verNum); 下载资源时&#xff0c;第一次下载某个资源&#xff0c;www.assetBundle必定为空。 解决办法&#xff1a;   引擎版本降到4.3.2或者升到4.3.4或更高。 这个bug绝对是…

sml完整形式_411的完整形式是什么?

sml完整形式411&#xff1a;信息 (411: Information) 411 is an abbreviation of “Information". 411是“信息”的缩写 。 It is an expression, which is commonly used in messaging or chatting on social media networking sites like Facebook, Yahoo Messenger, a…