动态规划 1.背包问题
原文链接:https://www.acwing.com/solution/content/1374/
文章目录
- 1. 题目介绍
- 2. 题解代码(C++)
- 2.1 版本1 二维
- 2.2 版本2 一维
- 2.3 版本3 优化输入
1. 题目介绍
有 N 件物品和一个容量为 V 的背包,每件物品有各自的价值且只能被选择一次,要求在有限的背包容量下,装入的物品总价值最大。
「0-1 背包」是较为简单的动态规划问题,也是其余背包问题的基础。
动态规划是不断决策求最优解的过程,「0-1 背包」即是不断对第 i 个物品的做出决策,「0-1」正好代表不选与选两种决定。
2. 题解代码(C++)
2.1 版本1 二维
(1)状态f[i][j]定义:在背包容量 为 j 下,考虑前 i 个物品(从前 i 个物品中任意挑选)的最优解(最大价值):
当前的状态依赖于之前的状态,可以理解为从初始状态f[0][0] = 0开始决策,有 N 件物品,则需要 N 次决策,每一次对第 i 件物品的决策,状态f[i][j]不断由之前的状态更新而来。
(2)当前背包容量不够(j < v[i]),则该状态一定是通过上一个状态不选择第i个物品而得到的。因此前 i 个物品背包容量 j 下的最优解即为前i−1 个物品背包容量 j 下的最优解,对应代码:f[i][j] = f[i - 1][j]。
(3)当前背包容量够,可以选,因此需要决策选与不选第 i 个物品:
- 选:f[i][j] = f[i - 1][j - v[i]] + w[i]。
- 不选:f[i][j] = f[i - 1][j] 。
我们的决策是如何取到最大价值,因此以上两种情况取 max() 。
#include<bits/stdc++.h>using namespace std;const int MAXN = 1005;
int v[MAXN]; // 体积
int w[MAXN]; // 价值
int f[MAXN][MAXN]; // f[i][j], j体积下前i个物品的最大价值 int main()
{int n, m; cin >> n >> m;for(int i = 1; i <= n; i++) cin >> v[i] >> w[i];for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++){// 当前背包容量装不进第i个物品if(j < v[i]) f[i][j] = f[i - 1][j];// 能装,需进行决策是否选择第i个物品else f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);} cout << f[n][m] << endl;return 0;
}
2.2 版本2 一维
将状态f[i][j]优化到一维f[j],实际上只需要做一个等价变形。
为什么可以这样变形呢?我们定义的状态f[i][j]可以求得任意合法的 i 与 j 最优解,但题目只需要求得最终状态f[n][m],因此我们只需要一维的空间来更新状态。
(1)状态 f[j] 定义:N 件物品,背包容量j下的最优解。
(2)注意枚举背包容量j必须从m开始。
(3)为什么一维情况下枚举背包容量需要逆序?在二维情况下,状态f[i][j]是由上一轮i - 1的状态得来的,f[i][j]与f[i - 1][j]是独立的。而优化到一维后,如果我们还是正序,则有f[较小体积]更新到f[较大体积],则本应该用第i-1轮的状态却用的是第i轮的状态。例如,当更新到f[i][j]时,用 f[i - 1][j - v[i]] 计算f[i][j],因为是从小到大枚举j,则在第i轮,更新到j时,j - v[i]一定已经被更新过了,所以此时用到的f[j - v[i]]实际上是第i轮的。而此时如果从大到小枚举j,在第i轮更新到f[i][j]时要用到的f[j - v[i]]在第i轮还没有被更新过,所以此时用到的f[j - v[i]]一定是上一轮,即第i-1轮的f[j - v[i]],刚好与原二维代码等价。
状态转移方程为:f[j] = max(f[j], f[j - v[i]] + w[i]) 。
for(int i = 1; i <= n; i++) for(int j = m; j >= 0; j--){if(j < v[i]) //f[i][j] = f[i - 1][j]; // 优化前f[j] = f[j]; // 优化后,该行自动成立,可省略。else //f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]); // 优化前f[j] = max(f[j], f[j - v[i]] + w[i]); // 优化后}
实际上,只有当枚举的背包容量 >= v[i] 时才会更新状态,因此我们可以修改循环终止条件进一步优化。
for(int i = 1; i <= n; i++)
{for(int j = m; j >= v[i]; j--) f[j] = max(f[j], f[j - v[i]] + w[i]);
}
关于状态f[j]的补充说明
二维下的状态定义f[i][j]是前 i 件物品,背包容量 j 下的最大价值。一维下,少了前 i 件物品这个维度,我们的代码中决策到第 i 件物品(循环到第i轮),f[j]就是前i轮已经决策的物品且背包容量 j 下的最大价值。
因此当执行完循环结构后,由于已经决策了所有物品,f[j]就是所有物品背包容量 j 下的最大价值。即一维f[j]等价于二维f[n][j]。
2.3 版本3 优化输入
我们注意到在处理数据时,我们是一个物品一个物品,一个一个体积的枚举。
因此我们可以不必开两个数组记录体积和价值,而是边输入边处理。
#include<bits/stdc++.h>using namespace std;const int MAXN = 1005;
int f[MAXN]; // int main()
{int n, m; cin >> n >> m;for(int i = 1; i <= n; i++) {int v, w;cin >> v >> w; // 边输入边处理for(int j = m; j >= v; j--)f[j] = max(f[j], f[j - v] + w);}cout << f[m] << endl;return 0;
}
动态规划 1.背包问题相关推荐
- Suzy心情很差因为被charge了late fee Day42 | 动态规划之背包问题,416. 分割等和子集
背包问题 01背包 Given n种物品,每种物品只有1个 每个物品有自己的重量.价值. 背包最大能装载的重量 动规五部曲--用二维数组 定义dp数组的含义:dp[ i ][ j ]表示[0,i]物品 ...
- 【算法与数据结构】—— 动态规划之背包问题
动态规划之背包问题 前面介绍了一些最常见的动态规划题型和对应解法,而实际上,动态规划最经典的题型非背包问题莫属,并且大多数人最初都是从背包问题入坑进而打开动态规划这一大门. 背包问题分为多种,其中最常 ...
- 动态规划之背包问题的一些基础简单入门题
前言 参考视频教程洛谷试练场 普及组 动态规划的背包问题 主要有01背包问题.完全背包问题.分组背包问题. 01背包问题一般从右往左推: 完全背包问题一般从左往右推: 分组背包一般用01的方法但需要记 ...
- c语言背包问题装字母,C语言动态规划之背包问题详解
01背包问题 给定n种物品,和一个容量为C的背包,物品i的重量是w[i],其价值为v[i].问如何选择装入背包的物品,使得装入背包中的总价值最大?(面对每个武平,只能有选择拿取或者不拿两种选择,不能选 ...
- 动态规划之背包问题——01背包
算法相关数据结构总结: 序号 数据结构 文章 1 动态规划 动态规划之背包问题--01背包 动态规划之背包问题--完全背包 动态规划之打家劫舍系列问题 动态规划之股票买卖系列问题 动态规划之子序列问题 ...
- 动态规划之背包问题(JAVA)
背包问题之前的C语言版本已经将思路解析的差不多,虽然还有些许错误需要改正,但大体思路是正确的,需要的读者请参阅动态规划之背包问题(C语言) 背包问题本身就是典型的动态规划问题,所以这里只给出动态规划的 ...
- 动态规划解决背包问题
动态规划解决背包问题 问题描述: (1)解法一: 解决思路:动态规划 状态索引范围:从1开始 价值数组,大小数组索引范围:从0开始 状态:F(i,j):前i个物品放入大小为j的背包中所获得的最大价值. ...
- 动态规划之背包问题总结
动态规划之背包问题总结 递推公式 遍历顺序 01背包遍历顺序 完全背包遍历顺序 参考链接:代码随想录 背包问题是动态规划中的重要的一部分,背包问题分为多种,只需要掌握常见的01背包和完全背包就行. ...
- ACM杂题——动态规划_背包问题
ACM杂题K - I NEED A OFFER!--动态规划_背包问题优化解法 题目描述 Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校 ...
- 【学习笔记整理】动态规划:背包问题之八大情况
[学习笔记整理]动态规划:背包问题之八大情况 一.01背包问题 二.完全背包问题 三.多重背包问题 四.混合背包问题 五.二维费用的背包问题 六.分组背包问题 七.背包问题求方案数 八.背包问题求具体 ...
最新文章
- java selectcommand_“对于不返回任何基表信息的 SelectCommand 不支持动态SQL生成”-奇怪的错误,不知道原因! | 学步园...
- Redis中RedisTemplate和Redisson管道的使用
- 32.C#--方法中使用out参数做登录判断
- flask-mail异步发送邮件_.NET Core使用FluentEmail发送邮件
- 老赖整治升级,不还钱直接扣微信钱包!
- 2020中国数字营销人才发展报告
- telnet IP不通/sybase central工具无法连接到数据库
- intellisense_SQL Server IntelliSense的使用和故障排除–适用于SQL Server 2012或更高版本
- 计算机基础win7桌面操作,windows7基本操作方法(零基础的人教学)-win7教程
- c++ 迭代器++和+1_C ++中的迭代器简介
- 《软件工程实践》第一次作业 之第3题
- java动态生成HTML文件
- 安信可——PB-03F烧录
- Win10 时间与Internet时间同步超时
- React通过后台图片路径,打包下载图片
- 计算机在聋校教学中有哪些作用,现代信息技术在聋校语文教学中的应用
- 2021年起重机司机(限桥式起重机)考试APP及起重机司机(限桥式起重机)免费试题
- 使用pydicom实现Dicom文件读取与CT图像窗宽窗位调整
- Bootloader(启动引导程序)--->u-boot
- 30s解决联想小新Air14指纹解锁失效问题
热门文章
- Enterprise Library 2.0 插件介绍:Avanade Integration Pack
- java环境变量代表的含义_java 环境变量的涵义
- OJ1079: a+b(多实例测试2)(C语言数组实现)
- 求整数的位数及各位数字之和(C语言)
- jira软件 linux 安装,JIRA使用教程:在Linux上安装JIRA
- java属性错误_在java中读取属性文件时发生文件未找到错误
- css 透明叠加_细品CSS(二)
- 信息学奥赛一本通 1392:繁忙的都市(city) | 洛谷 P2330 [SCOI2005]繁忙的都市
- OpenJudge NOI 1.2 05:填空:类型转换2
- 信息学奥赛一本通 1070:人口增长 | OpenJudge NOI 1.5 14:人口增长问题