原文链接: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.背包问题相关推荐

  1. Suzy心情很差因为被charge了late fee Day42 | 动态规划之背包问题,416. 分割等和子集

    背包问题 01背包 Given n种物品,每种物品只有1个 每个物品有自己的重量.价值. 背包最大能装载的重量 动规五部曲--用二维数组 定义dp数组的含义:dp[ i ][ j ]表示[0,i]物品 ...

  2. 【算法与数据结构】—— 动态规划之背包问题

    动态规划之背包问题 前面介绍了一些最常见的动态规划题型和对应解法,而实际上,动态规划最经典的题型非背包问题莫属,并且大多数人最初都是从背包问题入坑进而打开动态规划这一大门. 背包问题分为多种,其中最常 ...

  3. 动态规划之背包问题的一些基础简单入门题

    前言 参考视频教程洛谷试练场 普及组 动态规划的背包问题 主要有01背包问题.完全背包问题.分组背包问题. 01背包问题一般从右往左推: 完全背包问题一般从左往右推: 分组背包一般用01的方法但需要记 ...

  4. c语言背包问题装字母,C语言动态规划之背包问题详解

    01背包问题 给定n种物品,和一个容量为C的背包,物品i的重量是w[i],其价值为v[i].问如何选择装入背包的物品,使得装入背包中的总价值最大?(面对每个武平,只能有选择拿取或者不拿两种选择,不能选 ...

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

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

  6. 动态规划之背包问题(JAVA)

    背包问题之前的C语言版本已经将思路解析的差不多,虽然还有些许错误需要改正,但大体思路是正确的,需要的读者请参阅动态规划之背包问题(C语言) 背包问题本身就是典型的动态规划问题,所以这里只给出动态规划的 ...

  7. 动态规划解决背包问题

    动态规划解决背包问题 问题描述: (1)解法一: 解决思路:动态规划 状态索引范围:从1开始 价值数组,大小数组索引范围:从0开始 状态:F(i,j):前i个物品放入大小为j的背包中所获得的最大价值. ...

  8. 动态规划之背包问题总结

    动态规划之背包问题总结 递推公式 遍历顺序 01背包遍历顺序 完全背包遍历顺序 参考链接:代码随想录   背包问题是动态规划中的重要的一部分,背包问题分为多种,只需要掌握常见的01背包和完全背包就行. ...

  9. ACM杂题——动态规划_背包问题

    ACM杂题K - I NEED A OFFER!--动态规划_背包问题优化解法 题目描述 Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校 ...

  10. 【学习笔记整理】动态规划:背包问题之八大情况

    [学习笔记整理]动态规划:背包问题之八大情况 一.01背包问题 二.完全背包问题 三.多重背包问题 四.混合背包问题 五.二维费用的背包问题 六.分组背包问题 七.背包问题求方案数 八.背包问题求具体 ...

最新文章

  1. java selectcommand_“对于不返回任何基表信息的 SelectCommand 不支持动态SQL生成”-奇怪的错误,不知道原因! | 学步园...
  2. Redis中RedisTemplate和Redisson管道的使用
  3. 32.C#--方法中使用out参数做登录判断
  4. flask-mail异步发送邮件_.NET Core使用FluentEmail发送邮件
  5. 老赖整治升级,不还钱直接扣微信钱包!
  6. 2020中国数字营销人才发展报告
  7. telnet IP不通/sybase central工具无法连接到数据库
  8. intellisense_SQL Server IntelliSense的使用和故障排除–适用于SQL Server 2012或更高版本
  9. 计算机基础win7桌面操作,windows7基本操作方法(零基础的人教学)-win7教程
  10. c++ 迭代器++和+1_C ++中的迭代器简介
  11. 《软件工程实践》第一次作业 之第3题
  12. java动态生成HTML文件
  13. 安信可——PB-03F烧录
  14. Win10 时间与Internet时间同步超时
  15. React通过后台图片路径,打包下载图片
  16. 计算机在聋校教学中有哪些作用,现代信息技术在聋校语文教学中的应用
  17. 2021年起重机司机(限桥式起重机)考试APP及起重机司机(限桥式起重机)免费试题
  18. 使用pydicom实现Dicom文件读取与CT图像窗宽窗位调整
  19. Bootloader(启动引导程序)--->u-boot
  20. 30s解决联想小新Air14指纹解锁失效问题

热门文章

  1. Enterprise Library 2.0 插件介绍:Avanade Integration Pack
  2. java环境变量代表的含义_java 环境变量的涵义
  3. OJ1079: a+b(多实例测试2)(C语言数组实现)
  4. 求整数的位数及各位数字之和(C语言)
  5. jira软件 linux 安装,JIRA使用教程:在Linux上安装JIRA
  6. java属性错误_在java中读取属性文件时发生文件未找到错误
  7. css 透明叠加_细品CSS(二)
  8. 信息学奥赛一本通 1392:繁忙的都市(city) | 洛谷 P2330 [SCOI2005]繁忙的都市
  9. OpenJudge NOI 1.2 05:填空:类型转换2
  10. 信息学奥赛一本通 1070:人口增长 | OpenJudge NOI 1.5 14:人口增长问题