当前位置: 首页 > backend >正文

ch11题目参考思路

ch11 题目参考思路

算法 I ch11 - 动态规划:背包问题 I

01 背包计数

  • 知识点:01 背包计数

  • 思路:

    • 这一类计数问题与背包问题类似,但物品没有价值属性,只有重量属性 w[i],要计算有多少种选取物品的方案,使总重量恰好为 m。
    • 注意 dp 解决最值问题,是在不同选择中决策取 max 或 min,dp 解决计数问题,是在不同分类中按照计数原理统计。
    • dp[i][j] :前 i 个物品中,取出总重量恰好为 m 的物品选取方案数
      • 实际上还隐含着选取的物品要按照输入的顺序排列,这样才不会将相同物品排列顺序不同的情况重复统计。
    • 状态转移:
      • 第一类:不选第 i 个物品,dp[i-1][j]
      • 第二类:要选第 i 个物品(前提是 j >= w[i]),dp[i-1][j-w[i]]
      • 根据加法原理:dp[i][j] = dp[i-1][j] + dp[i-1][j-w[i]]
    • 边界:
      • 0 个物品里选出重量为 0,有“啥都不选”这一种方案,dp[0][0] = 1
      • 0 个物品里选出重量 > 0,不可能选出来,dp[0][1~m] = 0
    • 写对二维的写法后,尝试用滚动数组优化。

Money

  • 知识点:完全背包计数
  • 思路:
    • 本题将货币看作物品,货币面值看作物品重量,转换为背包模型。
    • 与 01 背包计数类似,区别是同一类物品可以取任意次,在加入一个第 i 类物品之前,背包里也可以有第 i 类物品,只需要将状态转移方程改为 dp[i][j] = dp[i-1][j] + dp[i][j-w[i]] 。
  • 代码:
    • 根据思路和前面题目的代码思考尝试。写对二维的写法后,尝试用滚动数组优化。

购物规划

  • 知识点:01 背包的应用

  • 思路:

    • 将两类商品分开处理比较方便,先处理第一类的物品,再处理第二类包包。

    • 第一类物品的处理与 01 背包相同,只是不能将容量限制为初始容量 m,因为后面还可能扩容,要按照扩容后的最大容量计算,计算出每个 dp[i][j] 的值。

    • 第二类包包计算扩展到容量 j 的最小代价 dp2[i][j]。

    • 最后枚举每个容量 j,对 (第一类获取的价值 - 第二类花费的价值)打擂台求最大值。

  • 代码:

    #include <bits/stdc++.h>
    using namespace std;const int maxn = 1010, maxm = 100010 * 2;
    using ll = long long;
    // f1[i][j] 的一维优化: 前 i 件物品,容量为 j 的包能装的最大价值
    // f2[i][j] 的一维优化: 前 i 件包包,买到容量为 j 的包能花的最小价钱
    ll f1[maxm], f2[maxm];
    int n, W, w[maxn], v[maxn], op[maxn];
    int main() {memset(f2, 0x3f, sizeof(f2));cin >> n >> W;for (int i = 0; i <= W; ++i) f2[i] = 0;for (int i = 1; i <= n; ++i) {cin >> op[i] >> w[i] >> v[i];}W += 1000 * 100;for (int i = 1; i <= n; ++i) {if (op[i] == 1)continue;for (int j = W; j >= w[i]; --j) {f2[j] = min(f2[j], f2[j - w[i]] + v[i]);}}for (int i = 1; i <= n; ++i) {if (op[i] == 2)continue;for (int j = W; j >= w[i]; --j) {f1[j] = max(f1[j], f1[j - w[i]] + v[i]);}}ll res = 0;// 枚举所有的背包容量,寻找最大能赚取的价值for (int j = 0; j <= W; ++j) {res = max(res, f1[j] - f2[j]);}cout << res;return 0;
    }
    

巨型背包

  • 知识点:01 背包、换维
  • 思路:
    • 本题也是 01 背包问题,只是数据范围比较特殊。如果按照之前的状态设计,第二维表示重量限制,开不了那么大的数组。

    • 需要进行“换维”,比较小的价值作为 dp 数组下标,大的重量作为 dp 数组的值。(这启示我们不一定题目怎么问就怎么设计 dp 状态,多角度考虑,换个状态表示也许能让复杂度更优)

    • dp[i][j]:前 i 个物品选出总价值为 j 时的最小总重量

      • 注意第二维表示价值,第二层 for 循环要根据最大总价值是多少来确定循环到多少。
    • 状态转移:

      • 不选第 i 个物品,dp[i-1][j]
      • 要选第 i 个物品(前提 j >= v[i]),dp[i-1][j-v[i]] + w[i]
      • 要最小总重量,所以在两种选择中取 min
    • 边界:

      • dp[0][0] = 0

      • 0 个物品不可能选出 > 0 的价值,用无穷大值 INF 来表示,dp[0][1~V] = INF。其中 V 表示最大总价值。

    • 结果:满足 dp[n][j] <= m 的最大的 j

  • 代码:
    • 根据 01 背包的代码和本题思路思考尝试。

装箱问题

  • 知识点:数字拼凑的判断
  • 思路:
    • 本题与背包计数问题类似,都是给出物品的重量或体积,没有价值。本题希望在容量 V 的限制下,选择物品拼凑出尽量大的体积。只要方案数 > 0,就说明能拼凑出来,可以根据背包计数的 dp[n][i] > 0 是否成立来判断总体积能否恰好达到 i。
      • 但这样有个问题,方案数计算结果可能很大,溢出数据范围,如果正确值 > 0,溢出后的错误值恰好 == 0,那么就会出错。
    • 只关心可以达到(true)和不能达到(false),用 bool 数组即可。
    • dp[i][j]:前 i 个物品中,能否选一些物品拼凑出恰好为 j 的总体积。
    • 状态转移
      • dp[i][j] = dp[i-1][j] | dp[i-1][j-w[i]] (这里的 | 是位运算中的“或”,用逻辑运算的 || 也可以)
      • 意思是如果“前 i - 1 个物品能拼凑出总体积 j”,那么前 i 个物品能拼凑出总体积 j。
      • 或者如果“前 i - 1 个物品能拼凑出总体积 j - w[i]”,那么选第 i 个物品加入,也就能拼凑出总体积 j 。
      • 思考如果是完全背包(每个物品能取无限次),状态转移如何修改。
    • 边界:
      • 0 个物品里选出重量为 0,“啥都不选”就能达到,dp[0][0] = true
      • 0 个物品里选出重量 > 0,无法达到,dp[0][1~m] = false
    • 结果:找到满足 dp[n][j] == true 的最大的 j,答案是 V - j 。
    • 本题有多种做法,例如比较直观的想法是用 dp[i][j] 表示前 i 个物品中,选出总体积不超过 j 的物品的最小剩余容量。
  • 代码:
    • 根据本题思路思考尝试。写对二维的写法后,尝试用滚动数组优化。

采药

  • 知识点:01 背包
  • 思路:
    • 把“时间”看作“重量”,问题转换为 01 背包问题。
  • 代码:
    • 根据 01 背包的代码思考尝试。

开心的金明

  • 知识点:01 背包
  • 思路:
    • 总钱数 n 看作背包的重量限制,物品的价格看作物品重量,价格与重要程度的乘积看作物品的价值,转换为 01 背包问题。
  • 代码:
    • 根据 01 背包的代码思考尝试。
http://www.xdnf.cn/news/8544.html

相关文章:

  • linux移植lvgl
  • 经典密码学和现代密码学的结构及其主要区别(1)维吉尼亚密码—附py代码
  • 模拟交易新维度:如何通过自营交易考试实现策略收益双提升?
  • PTA L1系列题解(C语言)(L1_105 -- L1_112)
  • OCC导入进度显示
  • Makefile快速入门
  • 直播预告 | 共探“数字化转型新引擎”,蓝卓工业互联网+AI对话夜等你来
  • 数字计数--数位dp
  • C 语言学习笔记(指针4)
  • golang 垃圾收集机制
  • 防火墙NAT地址组NAT策略安全策略
  • 50 python Matplotlib之Seaborn
  • Python爬虫实战:研究Cola框架相关技术
  • 开发工具整理
  • Python初始Flask框架
  • 敦煌网测评从环境搭建到风控应对,精细化运营打造安全测评体系
  • 【自定义类型-结构体】--结构体类型,结构体变量的创建和初始化,结构体内存对齐,结构体传参,结构体实现位段
  • ComfyUI Chroma解锁文生图新维度;OpenMathReasoning数学推理数据集,首个专注数学推理的高质量数据集
  • 深入探索 CSS 中的伪类:从基础到实战​
  • 文件目录名称无效?数据恢复全流程与常见问题解析
  • CMA/CNAS认证电子签章审计追踪 质检 LIMS 系统应用要点
  • 电子电路:什么是滤波器,什么优势高通滤波器?
  • Cookie、Session、JWT
  • 吃出 “颈” 松:痉挛性斜颈的饮食调养之道
  • Redis从入门到实战 - 原理篇
  • lua脚本实战—— Redis并发原子性陷阱
  • I-CON: A UNIFYING FRAMEWORK FOR REPRESENTATION LEARNING
  • 从Android开发聊技术
  • Python打卡5.23(day24)
  • 【和春笋一起学C++】(十五)字符串作为函数参数