本篇博客是基于Carl大佬的刷题笔记 (代码随想录) 进行总结的

另外加入了我自己的一些整理,特此记录,以防遗忘

几种在面试中常见的背包,其关系如下:

通过这个图,可以很清晰分清这几种常见背包之间的关系。

一、基本步骤

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

其实这五部里哪一步都很关键,确定递推公式和确定遍历顺序都具有规律性和代表性,所以下面为从这两点来对背包问题做的一些总结

二、背包递推公式

1.问能否能装满背包(或者最多装多少):dp[j]=max(dp[j],dp[j−nums[i]]+nums[i])dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])dp[j]=max(dp[j],dp[j−nums[i]]+nums[i]) ,对应题目如下:

  • 动态规划:416.分割等和子集
  • 动态规划:1049.最后一块石头的重量 II

2.问装满背包有几种方法:dp[j]+=dp[j−nums[i]]dp[j] += dp[j - nums[i]]dp[j]+=dp[j−nums[i]] ,对应题目如下:

  • 动态规划:494.目标和
  • 动态规划:518. 零钱兑换 II
  • 动态规划:377.组合总和Ⅳ
  • 动态规划:70. 爬楼梯进阶版(完全背包)

3.问背包装满最大价值:dp[j]=max(dp[j],dp[j−weight[i]]+value[i]);dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);dp[j]=max(dp[j],dp[j−weight[i]]+value[i]);,对应题目如下:

  • 动态规划:474.一和零

问装满背包所有物品的最小个数:dp[j]=min(dp[j−coins[i]]+1,dp[j]);dp[j] = min(dp[j - coins[i]] + 1, dp[j]);dp[j]=min(dp[j−coins[i]]+1,dp[j]); ,对应题目如下:

  • 动态规划:322.零钱兑换
  • 动态规划:279.完全平方数

三、遍历顺序

01背包

二维dp数组01背包先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历。

一维dp数组01背包只能先遍历物品再遍历背包容量,且第二层for循环是从大到小遍历

一维dp数组的背包在遍历顺序上和二维dp数组实现的01背包其实是有很大差异的!

完全背包

说完01背包,再看看完全背包。

纯完全背包的一维dp数组实现,先遍历物品还是先遍历背包都是可以的,且第二层for循环是从小到大遍历

但是仅仅是纯完全背包的遍历顺序是这样的,题目稍有变化,两个for循环的先后顺序就不一样了。

如果求组合数就是外层for循环遍历物品,内层for遍历背包

如果求排列数就是外层for遍历背包,内层for循环遍历物品

相关题目如下:

  • 求组合数:动态规划:518.零钱兑换II
  • 求排列数:动态规划:377. 组合总和 Ⅳ、动态规划:70. 爬楼梯进阶版(完全背包)

如果求最小数,那么两层for循环的先后顺序就无所谓了,相关题目如下:

  • 求最小数:动态规划:322. 零钱兑换、动态规划:279.完全平方数

对于背包问题,其实递推公式算是容易的,难是难在遍历顺序上,如果把遍历顺序搞透,才算是真正理解了

四、总结

这篇背包问题总结篇是对背包问题的高度概括,讲最关键的两步:递推公式和遍历顺序,结合力扣上的题目全都抽象出来了

而且每一个点,都给出了对应的力扣题目

五、代码

01背包问题的母题(代码如下)

#include<iostream>
#include<vector>
#include<algorithm>
#include<string>using namespace std;int test_01_package(vector<int> &value, vector<int> &weight, int bagWeight)
{// 使用dp算法求解最大容量为4的背包可以装载物品的最大价值// 1.创建dp数组 dp[i][j]表示容量为j的背包的从物品0~i中任取物品后可装载的最大价值vector<vector<int>> dp(weight.size(), vector<int>(bagWeight + 1));// 3.初始化dp数组for (size_t i = 0; i < weight.size(); i++) {dp[i][0] = 0;}for (int j = 0; j < weight[0]; j++) {dp[0][j] = 0;}for (int j = weight[0]; j <= bagWeight; j++) {dp[0][j] = value[0];}// 2.递归公式// dp[i][j] 表示容量为j的背包的从物品0~i中任取物品后可装载的最大价值// 其值的获取可以由两种情况递推得到(分情况讨论)//      a.肯定不取物品i             dp[i][j] = dp[i-1][j] //      b.既可以取也可以不取物品i     max(dp[i-1][j-weight[i]] + value, dp[i-1][j])// 4.遍历for (size_t i = 1; i < weight.size(); i++) {for (int j = 1; j <= bagWeight; j++){if(j < weight[i])dp[i][j] = dp[i - 1][j];elsedp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);}}// 5.返回结果return dp[weight.size() - 1][bagWeight];
}/** 1.dp数组创建 dp[j] 表示容量为i的背包所能装载的最大价值* 3.初始化 dp[j]数组 在只有一个物品0可选时 选该物品dp[j]!=0 不选该物品dp[j]==0 因此dp数组应该初始化为0*   由于是 vector<int> 编译器默认初始化为0 故这步可以省略* 2.递推公式*   dp[j] = max(dp[j], dp[j - weight[j]] + value[i])*   本质上是二维dp数组中的第i行复用了dp数组中的第i-1行 同时为了避免dp[i][j]覆盖了dp[i-1][j]*   进一步影响dp[i][j++...]的递推求解 所以遍历顺利应该改成从大到小 从右向左的顺序* 4.遍历* 5.返回最终值*/
int test_01_package_scroll(vector<int>& value, vector<int>& weight, int bagWeight)
{vector<int> dp(bagWeight + 1);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]);}}return dp[bagWeight];
}int main() {// 1.物品价值vector<int> value = {15, 20, 30};// 2.物品重量vector<int> weight = {1, 3, 4};// 3.背包容量int bagWeight = 4;cout << "test_01_package:";cout << test_01_package(value, weight, bagWeight) << endl;cout << "test_01_package_scroll:";cout << test_01_package_scroll(value, weight, bagWeight) << endl;return 0;
}

完全背包问题的母题(代码如下)

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;/** 对于完全背包问题, 有如下几条结论:* 1、因为是完全背包问题,所以正序遍历dp[j]* 2、如果是组合问题,应该先遍历物品(外循环) 再遍历背包容量(内循环)*      因为物品在外边循环,假如背包容量为4, 物品被遍历到的顺序是[1, 3, 4...], 那么物品的顺序只能是{1, 3} 而不能是{3, 1}* 3、如果是排列问题,应该先遍历背包容量(外循环) 再遍历物品(内循环)*/int test_completePackage(vector<int> &value, vector<int> &weight, int bagweight)
{// 1.dp数组vector<int> dp(bagweight + 1);// 2.初始化// dp[0] = 0;// 3.递归公式// dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);// 4.遍历for (size_t i = 0; i < value.size(); i++){for (int j = weight[i]; j <= bagweight; j++){dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);}}// 5.返回结果return dp[bagweight];
}int main() {vector<int> weight = {1, 3, 4};vector<int> value = {15, 20, 30};int bagWeight = 4;cout << test_completePackage(value, weight, bagWeight) << endl;return 0;
}

多重背包问题的母题(代码如下)

/** 多重背包问题* 指定背包重量为j 求解背包容量为j时 从下属数组描述的物品中选取 试问该背包所能装载的最大价值是多少?其中物品的数目是一个有限值* 物品的重量为weight[]表示* 物品的价值为value[]表示* 物品的数目为nums[]表示---->注意:这里正是多重背包问题与01背包问题、完全背包问题的区别之处** 解题思路: 将多重背包平铺开来,就变成了01背包问题 如下所示:*      物品重量 weight[i] = {1, 3, 4};*      物品价值 value[i] = {15, 20, 30};*      物品数目 nums[i] = {2, 3, 2};* 平铺后等价于--->*      物品重量 weight[i] = {1, 1, 3, 3, 3, 4, 4};*      物品价值 value[i] = {15, 15, 15, 20, 20, 20, 30, 30};*      物品数目 nums[i] = {1, 1, 1, 1, 1, 1, 1};* 也就可以直接使用01问题解决了*/#include <algorithm>
#include <iostream>
#include <vector>using namespace std;int test_MultiPackage(vector<int> w, vector<int> v, vector<int> n, int bagWeight) {// 一.平铺问题变成01背包for (size_t i = 0; i < n.size(); i++){while (n[i] > 1){w.push_back(w[i]);v.push_back(v[i]);n[i]--;}}// 二.按照01问题解决vector<int> dp(bagWeight + 1);dp[0] = 0;for (size_t i = 0; i < w.size(); i++){  for (int j = bagWeight; j >= w[i] ; j--){dp[j] = max(dp[j], dp[j - w[i]] + v[i]);}}return dp[bagWeight];
}int main() {vector<int> weight = {1, 3, 4};vector<int> value = {15, 20, 30};vector<int> nums = {2, 3, 2};int bagWeight = 10;cout << test_MultiPackage(weight, value, nums, bagWeight) << endl;return 0;
}

动态规划之背包问题---01背包---完全背包---多重背包相关推荐

  1. 动态规划之背包问题——01背包

    算法相关数据结构总结: 序号 数据结构 文章 1 动态规划 动态规划之背包问题--01背包 动态规划之背包问题--完全背包 动态规划之打家劫舍系列问题 动态规划之股票买卖系列问题 动态规划之子序列问题 ...

  2. 背包问题-【01背包】【完全背包】【多重背包】【多限定条件背包】

    背包问题 给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高. 可参考https://www.cnblogs.com/-guz/p/9866118.h ...

  3. 动态规划之背包问题 01背包

    什么是01背包? 有n件物品和一个最多能背重量为w 的背包.第i件物品的重量是weight[i],得到的价值是value[i] .每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大. 首先, ...

  4. 小明打联盟 牛客(背包dp,多重背包)

    链接:https://ac.nowcoder.com/acm/problem/14553 来源:牛客网 题目描述 小明很喜欢打游戏,现在已知一个新英雄即将推出,他同样拥有四个技能,其中三个小技能的释放 ...

  5. 【python】一篇讲透背包问题(01背包 完全背包 多重背包 二维费用背包)

    面对背包问题,有一个很重要的方程式:状态转移方程式 所以每一种背包问题我都会给出状态转移方程式 #01背包 什么是01背包型问题? 先给大家感受一下01背包型问题: 给定n种物品和一背包.物品i的重量 ...

  6. c++ 多重背包状态转移方程_【模板】各种背包问题amp;讲解

    [模板]各种背包问题&讲解  背包问题集合 一般来说,动态规划(DP)都是初学者最难闯过的一关,而在这里详细解说动态规划的一种经典题型:背包问题. 这里介绍的背包分为以下几种:01背包,完全背 ...

  7. 01背包模板、全然背包 and 多重背包(模板)

    转载请注明出处:http://blog.csdn.net/u012860063 贴一个自觉得解说不错的链接:http://www.cppblog.com/tanky-woo/archive/2010/ ...

  8. 01背包模板、完全背包 and 多重背包

    转载请注明出处:http://blog.csdn.net/u012860063 讲解链接:http://www.cppblog.com/tanky-woo/archive/2010/07/31/121 ...

  9. 【qduoj - 142】 多重背包(0-1背包的另类处理,dp)

    题干: ycb的ACM进阶之路 Description ycb是个天资聪颖的孩子,他的梦想是成为世界上最伟大的ACMer.为此,他想拜附近最有威望的dalao为师.dalao为了判断他的资质,给他出了 ...

最新文章

  1. 图片像素、英寸、厘米之间的单位换算
  2. AI一分钟 | Windows负责人离职;华为2017年收入6036亿元,净利475亿元
  3. c++ char **argv 赋值
  4. 外部函数获取内部函数变量_一维随机变量的分布函数
  5. vue 取数组第一个值_Vue如何循环提取对象数组中的值
  6. java调用jndi出错,Webshpere数据源错误:无法查找JNDI名称
  7. postgreSQL源码分析——索引的建立与使用——GIST索引(2)
  8. iterator遍历_HashMap 的 7 种遍历方式与性能分析!(强烈推荐)
  9. 【转】转贴 poj分类
  10. Java中将ResultSet结果集转换为List
  11. sklearn 文本处理
  12. [BZOJ1007][HNOI2008]水平可见直线 计算几何
  13. 【BZOJ 1082】[SCOI2005]栅栏 二分+dfs
  14. 闽什么什么院第二课堂网课破解-----微信内置浏览器
  15. Vue 关闭浏览器清除Cookies
  16. 解决“你的许可证不是正版,并且你可能是盗版软件的受害者。使用正版Office,避免干扰并保护你的文件安全。”
  17. Part 1 ——ActiveMQ 概述
  18. 一直以来伴随我的一些学习习惯(二):时间管理
  19. 毕业设计 嵌入式 智能火灾报警器设计与实现
  20. 写博客--用文字整理生命

热门文章

  1. 怎样用命令行方式添加打印机端口? (已解决)
  2. cad2016中选择全图字体怎么操作_想知道大神是怎么做PPT的吗?一个插件,帮你省出俩小时!...
  3. 华为手机自带功能居然可以把来电铃声改成视频?这下可涨知识了
  4. 矢量 报表 html,矢量文件是啥意思
  5. 【Java进阶】Java并发类库提供的线程池有哪几种? 分别有什么特点?
  6. WORD出现两个mathtype解决办法,超简单
  7. 计算机毕业设计之java+ssm基于web的智能卤菜销售平台
  8. 事件回顾:B站遭攻击导致用户节操值尽失,那一晚究竟发生了什么?
  9. 省电ipad考虑关闭和onedrive恢复goodnote
  10. 查找相似网站的方法和地址