《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…

《dp补卡——多重背包》

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

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补卡——子序列问题》

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

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

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

explain用法

explain用法 EXPLAIN SELECT …… 变体&#xff1a; 1. EXPLAIN EXTENDED SELECT …… 将执行计划“反编译”成SELECT语句&#xff0c;运行SHOW WARNINGS 可得到被MySQL优化器优化后的查询语句 2. EXPLAIN PARTITIONS SELECT …… 用于分区表的EXPLAIN 执行计划包含的信息 id…

转:Google论文之三----MapReduce

文章来自于&#xff1a;http://www.cnblogs.com/geekma/p/3139823.html MapReduce&#xff1a;大型集群上的简单数据处理 摘要 MapReduce是一个设计模型&#xff0c;也是一个处理和产生海量数据的一个相关实现。用户指定一个用于处理一个键值&#xff08;key-value&#xff09;…

《DBNotes:Join算法的前世今生》

目录NestLoopJoin算法Simple Nested-Loop JoinIndex Nested-Loop JoinBlock Nested-Loop JoinBatched Key AccessHash Join算法In-Memory Join(CHJ)On-Disk Hash Join参考链接在8.0.18之前&#xff0c;MySQL只支持NestLoopJoin算法&#xff0c;最简单的就是Simple NestLoop Joi…

UNITY3D与iOS交互解决方案

原地址&#xff1a;http://bbs.18183.com/thread-456979-1-1.html 本帖最后由 啊,将进酒 于 2014-2-27 11:17 编辑 “授人以鱼&#xff0c;不如授人以渔”&#xff0c;以UNITY3D调用iOS版的91SDK为例&#xff0c;利用C# / C / OBJ-C交互原理,本文将详细介绍UNITY3D与iOS之间交互…

AP in R

AP聚类算法是目前十分火的一种聚类算法&#xff0c;它解决了传统的聚类算法的很多问题。不仅简单&#xff0c;而且聚类效果还不错。这里&#xff0c;把前两天学习的AP算法在R语言上面的模拟&#xff0c;将个人笔记拿出来与大家分享一下&#xff0c;不谈AP算法的原理&#xff0c…

nginx 模块解析

nginx的模块非常之多&#xff0c;可以认为所有代码都是以模块的形式组织&#xff0c;这包括核心模块和功能模块&#xff0c;针对不同的应用场合&#xff0c;并非所有的功能模块都要被用到&#xff0c;附录A给出的是默认configure&#xff08;即简单的http服务器应用&#xff09…

《LeetcodeHot100非困难题补录》

最近比较闲&#xff0c;也比较焦虑&#xff0c;刷刷题吧 目录11. 盛最多水的容器22. 括号生成31. 下一个排列48. 旋转图像49. 字母异位词分组56. 合并区间75. 颜色分类79. 单词搜索114. 二叉树展开为链表141. 环形链表148. 排序链表152. 乘积最大子数组169. 多数元素207. 课程表…

《MySQL8.0.22:Lock(锁)知识总结以及源码分析》

目录1、关于锁的一些零碎知识&#xff0c;需要熟知事务加锁方式&#xff1a;Innodb事务隔离MVCC多版本并发控制常用语句 与 锁的关系意向锁行级锁2、锁的内存结构以及一些解释3、InnoDB的锁代码实现锁系统结构lock_sys_tlock_t 、lock_rec_t 、lock_table_tbitmap锁的基本模式的…

《Linux杂记:一》

目录CPU负载和CPU利用率CPU负载很高,利用率却很低的情况负载很低,利用率却很高常用linux命令常用的文件、目录命令常用的权限命令常用的压缩命令CPU负载和CPU利用率 可以通过 uptime , w 或者 top 命令看到CPU的平均负载。 Load Average :负载的3个数字,比如上图的0.57、0.4…

Iptables入门教程

转自&#xff1a;http://drops.wooyun.org/tips/1424 linux的包过滤功能&#xff0c;即linux防火墙&#xff0c;它由netfilter 和 iptables 两个组件组成。 netfilter 组件也称为内核空间&#xff0c;是内核的一部分&#xff0c;由一些信息包过滤表组成&#xff0c;这些表包含内…

No identities are available for signing 的解决办法

今天重新上传做好的app提交到app store&#xff0c;结果就出现标题上的错误。“No identities are available for signing”。 以后碰到这样的问题按照下面几个步骤来做&#xff1a; 进入Distribution -----下载发布证书 -----双击安装-----重启Xcode就能上传了 其他细节 如果再…

匿名方法和Lambda表达式

出于MVVM学习的需要&#xff0c;复习下匿名方法和Lambda表达式&#xff0c;因为之前用的也比较少&#xff0c;所以用的也不是很熟练&#xff0c;Baidu下相关的知识&#xff0c;写了这个Demo&#xff0c;目标是用简单的方法展示这个怎么用。 这里偏重的和LINQ中的Lambda表达式 …

烂橘子

Problem Statement: 问题陈述&#xff1a; Given a matrix of dimension r*c where each cell in the matrix can have values 0, 1 or 2 which has the following meaning: 给定尺寸r * C的矩阵&#xff0c;其中矩阵中的每个单元可以具有其具有以下含义的值0&#xff0c;1或2…