【动态规划】风扫枯杨,满地堆黄叶 - 9. 完全背包问题
本篇博客给大家带来的是完全背包问题之动态规划解法技巧.
🐎文章专栏: 动态规划
🚀若有问题 评论区见
❤ 欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .
王子,公主请阅🚀
- 要开心
- 要快乐
- 顺便进步
- 1. 完全背包
- 2. 零钱兑换
要开心
要快乐
顺便进步
1. 完全背包
题目链接: DP42 【模板】完全背包
题目内容:
描述
你有一个背包,最多能容纳的体积是V。
现在有n种物品,每种物品有任意多个,第i种物品的体积为
vi ,价值为wi 。
(1)求这个背包至多能装多大价值的物品?
(2)若背包恰好装满,求至多能装多大价值的物品?
输入描述:
第一行两个整数n和V,表示物品个数和背包体积。
接下来n行,每行两个数
vi 和 wi,表示第i种物品的体积和价值。
1≤n,V≤1000
输出描述:
输出有两行,第一行输出第一问的答案,第二行输出第二问的答案,如果无解请输出0。
解题须知:
完全背包问题与01背包问题的区别:
01背包问题中一种物品只能选一个.
完全背包问题种一种物品能选多个.
第一 先解决第一问
1. 状态表示
dp[i][j]表示从前 i 个物品中选,总体积不超过 j,所有选法中能选出的最大价值.
2. 状态转移方程
与01背包问题一样,
根据最后一个物品的情况来划分问题:

最后一个物品不选:dp[i][j] = dp[i-1][j];
选一个: dp[i][j] = dp[i-1][j-v[i]] + w[i];
选两个: dp[i][j] = dp[i-1][j-2×v[i]] + 2×w[i];
…
选k个: dp[i][j] = dp[i-1][j-k×v[i]] + k×w[i];
上述多种情况求最大值:
dp[i][j] = max(dp[i-1][j],dp[i-1][j-v[i]]+w[i],dp[i-1][j-2×v[i]] + 2×w[i],…,dp[i-1][j-k×v[i]] + k×w[i]); ①
dp[i][j-v[i]] + w[i] = max(dp[i-1][j-v[i]]+w[i],dp[i-1][j-2×v[i]] + 2×w[i],…,dp[i-1][j-h×v[i]] + h×w[i]); ②
先说结论: ①式中的k 一定等于②中的h.这是为什么呢?
在状态表示中,我们定义dp[i][j]表示从前 i 个物品中选,总体积不超过 j ,所有选法中能选出的最大价值.
随着所选物品越多, j 一定会趋于0, 无论是①还是②都一定是这样的, 所以k = h;
状态转移方程只能是有限个递推公式,所以需要化简上述式子,那么由①和②可得:
dp[i][j] = max(dp[i-1][j],dp[i][j-v[i]]+w[i]);
dp[i][j-v[i]]+w[i]式子需要保证 j >= v[i]
3. 初始化
多创建一行一列,处理两个细节:
Ⅰdp表与原数组的下标对应关系:
不做任何处理时是: i – i-1
但此题, 读入有效元素是从下标1开始的,
所以 i – i
Ⅱ初始化虚拟节点:
第一行,根据定义 当 i = 0时,没有物品,无论怎么选最大价值都是0.
第一列(除第一个位置)无需初始化, 因为 j >= v[i] 只有dp[0][0]满足.

4. 填表顺序
看状态转移方程,
要想得到dp[i][j] 就得知道dp[i-1][j]和dp[i][j-v[i]]+w[i];
所以从上往下填写每一行
每一行从左往右填写.
5. 返回值
根据状态表示和题目要求
打印 dp[n][V]即可.
6. 优化

第二 解决第二问
1. 状态表示
dp[i][j]表示从前 i 个物品中选,总体积等于 j,所有选法中能选出的最大价值.
2. 状态转移方程
根据最后一个物品的情况来划分问题:

最后一个物品不选:dp[i][j] = dp[i-1][j];
选一个: dp[i][j] = dp[i-1][j-v[i]] + w[i];
选两个: dp[i][j] = dp[i-1][j-2×v[i]] + 2×w[i];
…
选k个: dp[i][j] = dp[i-1][j-k×v[i]] + k×w[i];
上述多种情况求最大值:
dp[i][j] = max(dp[i-1][j],dp[i-1][j-v[i]]+w[i],dp[i-1][j-2×v[i]] + 2×w[i],…,dp[i-1][j-k×v[i]] + k×w[i]); ①
dp[i][j-v[i]] + w[i] = max(dp[i-1][j-v[i]]+w[i],dp[i-1][j-2×v[i]] + 2×w[i],…,dp[i-1][j-h×v[i]] + h×w[i]); ②
先说结论: ①式中的k 一定等于②中的h.这是为什么呢?
在状态表示中,我们定义dp[i][j]表示从前 i 个物品中选,总体积不超过 j ,所有选法中能选出的最大价值.
随着所选物品越多, j 一定会趋于0, 无论是①还是②都一定是这样的, 所以k = h;
状态转移方程只能是有限个递推公式,所以需要化简上述式子,那么由①和②可得:
dp[i][j] = max(dp[i-1][j],dp[i][j-v[i]]+w[i]);
dp[i][j-v[i]]+w[i]式子需要保证 j >= v[i]
第二问需要多考虑一个细节, 所选择的 i 物品并不一定能够保证 j-v[i] 恰好等于0, 有可能背包体积有剩余.
当背包体积有剩余时,规定dp[i][j-v[i]] = -1;
于是需要满足条件:
j - v[i] >= 0 && dp[i][j-v[i]] != -1;
3. 初始化
多创建一行一列,处理两个细节:
Ⅰdp表与原数组的下标对应关系:
不做任何处理时是: i – i-1
但此题, 读入有效元素是从下标1开始的,
所以 i – i
Ⅱ初始化虚拟节点:
第一行,根据定义 当 i = 0且j >= 1时,没有物品可选, 意味着背包体积有剩余.故dp[0][j] = -1;
第一列(除第一个位置)无需初始化, 因为 j >= v[i] 只有dp[0][0]满足.

4. 填表顺序
看状态转移方程,
要想得到dp[i][j] 就得知道dp[i-1][j]和dp[i][j-v[i]]+w[i];
所以从上往下填写每一行
每一行从左往右填写.
5. 返回值
根据状态表示和题目要求
打印 dp[n][V]即可.
6. 优化

第三 代码实现
//优化前:// Scanner in = new Scanner(System.in);// // 注意 hasNext 和 hasNextLine 的区别// int N = 1010;// int[][] dp = new int[N][N];// int[][] dp2 = new int[N][N];// int[] v = new int[N];// int[] w = new int[N];// int n = in.nextInt();// int V = in.nextInt();// for(int i = 1;i <= n;i++) {// v[i] = in.nextInt();// w[i] = in.nextInt();// }// //解决第一问// for(int i = 1;i <= n;++i) {// for(int j = 0;j <= V;++j) {//j需要从0开始,因为初始化的时候并没有考虑第一列的全部位置,只考虑了第一列的第一个位置.// dp[i][j] = dp[i-1][j];// if(j >= v[i]) {// dp[i][j] = Math.max(dp[i][j],dp[i][j-v[i]]+w[i]);// }// }// }// System.out.println(dp[n][V]);// //解决第二问// for(int i = 1;i <= V;++i) {// dp2[0][i] = -1;// }// for(int i = 1;i <= n;++i) {// for(int j = 0;j <= V;++j) {//j需要从0开始,因为初始化的时候并没有考虑第一列的全部位置,只考虑了第一列的第一个位置.// dp2[i][j] = dp2[i-1][j];// if(j >= v[i] && dp2[i][j-v[i]] != -1) {// dp2[i][j] = Math.max(dp2[i][j],dp2[i][j-v[i]]+w[i]);// }// }// }// System.out.println(dp2[n][V] == -1 ? 0 : dp2[n][V]);//优化后:Scanner in = new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别int N = 1010;int[] dp = new int[N];int[] dp2 = new int[N];int[] v = new int[N];int[] w = new int[N];int n = in.nextInt();int V = in.nextInt();for(int i = 1;i <= n;i++) {v[i] = in.nextInt();w[i] = in.nextInt();}//解决第一问for(int i = 1;i <= n;++i) {for(int j = 0;j <= V;++j) {//j需要从0开始,因为初始化的时候并没有考虑第一列的全部位置,只考虑了第一列的第一个位置.if(j >= v[i]) {dp[j] = Math.max(dp[j],dp[j-v[i]]+w[i]);}}}System.out.println(dp[V]);//解决第二问for(int i = 1;i <= V;++i) {dp2[i] = -1;}for(int i = 1;i <= n;++i) {for(int j = 0;j <= V;++j) {//j需要从0开始,因为初始化的时候并没有考虑第一列的全部位置,只考虑了第一列的第一个位置.dp2[j] = dp2[j];if(j >= v[i] && dp2[j-v[i]] != -1) {dp2[j] = Math.max(dp2[j],dp2[j-v[i]]+w[i]);}}}System.out.println(dp2[V] == -1 ? 0 : dp2[V]);}
}
2. 零钱兑换
题目链接: 322. 零钱兑换
题目内容:
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例 2:
输入:coins = [2], amount = 3
输出:-1
示例 3:
输入:coins = [1], amount = 0
输出:0
第一 动态规划
1. 状态表示
dp[i][j]表示从前 i 个硬币中选,总金额等于 j,所有选法中能选出的最少硬币个数.
2. 状态转移方程
根据最后一个物品的情况来划分问题:

最后一个物品不选:dp[i][j] = dp[i-1][j];
选一个: dp[i][j] = dp[i-1][j-coins[i]] + 1;
选两个: dp[i][j] = dp[i-1][j-2×coins[i]] + 2;
…
选k个: dp[i][j] = dp[i-1][j-k×coins[i]] + k;
上述多种情况求最小值:
dp[i][j] = min(dp[i-1][j],dp[i-1][j-coins[i]]+1,dp[i-1][j-2×coins[i]] + 2,…,dp[i-1][j-k×coins[i]] + k); ①
dp[i][j-v[i]] + 1 = min(dp[i-1][j-coins[i]]+1,dp[i-1][j-2×coins[i]] + 2,…,dp[i-1][j-h×coins[i]] + h); ②
先说结论: ①式中的k 一定等于②中的h.这是为什么呢?
在状态表示中,我们定义dp[i][j]表示从前 i 个硬币中选,总金额不超过 j ,所有选法中能选出的最少硬币个数.
随着所选硬币越多, j 一定会趋于0, 无论是①还是②都一定是这样的, 所以k = h;
状态转移方程只能是有限个递推公式,所以需要化简上述式子,那么由①和②可得:
dp[i][j] = max(dp[i-1][j],dp[i][j-coins[i]]+1);
dp[i][j-coins[i]]+1式子需要保证 j >= v[i]
还需要多考虑一个细节, 所选择的 i 硬币并不一定能够保证 j-coins[i] 恰好等于0, 有可能背包有剩余.
当背包有剩余时,规定dp[i][j-硬币[i]] = 0x3f3f3f3f;
于是需要满足条件:
j - coins[i] >= 0 && dp[i][j-coins[i]] != 0x3f3f3f3f;
3. 初始化
多创建一行一列,处理两个细节:
Ⅰdp表与原数组的下标对应关系:
i – i-1
Ⅱ初始化虚拟节点:
第一行,根据定义 当 i = 0且j >= 1时,没有硬币可选, 意味着背包有剩余.故dp[0][j] = 0x3f3f3f3f;
第一列(除第一个位置)无需初始化, 因为 j >= coins[i] 只有dp[0][0]满足.

4. 填表顺序
看状态转移方程,
要想得到dp[i][j] 就得知道dp[i-1][j]和dp[i][j-coins[i]]+1;
所以从上往下填写每一行
每一行从左往右填写.
5. 返回值
根据状态表示和题目要求
return dp[coins.length][amount]即可.
6. 优化

第二 代码实现
class Solution {public int coinChange(int[] coins, int amount) {//优化前:// int n = coins.length;// int[][] dp = new int[n+1][amount+1];// //2.初始化// for(int i = 1;i <= amount;++i) {// dp[0][i] = Integer.MAX_VALUE;// } // //3.填表// for(int i = 1;i <= n;++i) {// for(int j = 0;j <= amount;++j) {//j需要从0开始,因为初始化的时候并没有考虑第一列的全部位置,只考虑了第一列的第一个位置.// dp[i][j] = dp[i-1][j];// if(j >= coins[i-1] && dp[i][j-coins[i-1]] != Integer.MAX_VALUE) {// dp[i][j] = Math.min(dp[i][j],dp[i][j-coins[i-1]]+1);// }// }// }// return dp[n][amount] == Integer.MAX_VALUE ? -1 : dp[n][amount];//优化后:int n = coins.length;int[] dp = new int[amount+1];//2.初始化for(int i = 1;i <= amount;++i) {dp[i] = 0x3f3f3f3f;} //3.填表for(int i = 1;i <= n;++i) {for(int j = 0;j <= amount;++j) {//j需要从0开始,因为初始化的时候并没有考虑第一列的全部位置,只考虑了第一列的第一个位置.if(j >= coins[i-1] && dp[j-coins[i-1]] != 0x3f3f3f3f) {dp[j] = Math.min(dp[j],dp[j-coins[i-1]]+1);}}}return dp[amount] == 0x3f3f3f3f ? -1 : dp[amount];}
}
本篇博客到这里就结束啦, 感谢观看 ❤❤❤
🐎期待与你的下一次相遇😊😊😊
相关文章:
【动态规划】风扫枯杨,满地堆黄叶 - 9. 完全背包问题
本篇博客给大家带来的是完全背包问题之动态规划解法技巧. 🐎文章专栏: 动态规划 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅🚀 要开心要快乐顺…...
BGP基础协议详解
BGP基础协议详解 一、BGP在企业中的应用二、BGP概述2.1 BGP的特点2.2 基本配置演示2.3 抓包观察2.4 BGP的特征三、BGP对等体关系四、bgp报文4.1 BGP五种报文类型(重点)4.2 BGP报文格式-报文头格式4.3 Open报文格式4.4 Update报文格式4.5 Notification报文格式4.6 Route-refre…...
LeetCode刷题---数组---840
矩阵中的幻方 https://leetcode.cn/problems/magic-squares-in-grid/submissions/598584907/ 题目: 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成…...
Visual Studio踩过的坑
统计Unity项目代码行数 编辑-查找和替换-在文件中查找 查找内容输入 b*[^:b#/].*$ 勾选“使用正则表达式” 文件类型留空 也有网友做了指定,供参考 !*\bin\*;!*\obj\*;!*\.*\*!*.meta;!*.prefab;!*.unity 打开Unity的项目 注意:只是看࿰…...
【深度学习入门实战】基于Keras的手写数字识别实战(附完整可视化分析)
本人主页:机器学习司猫白 ok,话不多说,我们进入正题吧 项目概述 本案例使用经典的MNIST手写数字数据集,通过Keras构建全连接神经网络,实现0-9数字的分类识别。文章将包含: 关键概念图解完整实现代码训练过程可视化模型效果深度分析环境准备 import numpy as np impo…...
SkyWalking 10.1.0 实战:从零构建全链路监控,解锁微服务性能优化新境界
文章目录 前言一、集成SkyWalking二、SkyWalking使用三、SkyWalking性能剖析四、SkyWalking 告警推送4.1 配置告警规则4.2 配置告警通知地址4.3 下发告警信息4.4 测试告警4.5 慢SQL查询 总结 前言 在传统监控系统中,我们通过进程监控和日志分析来发现系统问题&…...
计算机毕业设计——Springboot的旅游管理
🎉**欢迎来到琛哥的技术世界!**🎉 📘 博主小档案: 琛哥,一名来自世界500强的资深程序猿,毕业于国内知名985高校。 🔧 技术专长: 琛哥在深度学习任务中展现出卓越的能力&a…...
【通俗易懂说模型】反向传播(附多元分类与Softmax函数)
🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀深度学习_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. …...
Kickstart自动化安装过程中自动选择较小的磁盘安装操作系统
Kickstart自动化安装过程中自动选择较小的磁盘安装操作系统 需求 在实际生成操作过程中,一般会遇到物理服务器存在多块盘的情况。 安装过程中,磁盘的标签是随机分配的,并不是空间较小的盘,就会使用较小的磁盘标签 而需求往往需要…...
128,【1】buuctf [极客大挑战 2019]PHP
进入靶场 提示了备份文件 抓包,扫描 扫描出了两个有反应的 访问index.php没反应,但www.zip成功下载了文件 index.php里得到如下有用信息 <?phpinclude class.php;$select $_GET[select];$resunserialize($select);?> 所以我们要通过GET 方…...
3.3 学习UVM中的uvm_driver 类分为几步?
文章目录 前言1. 定义2. 核心功能3. 适用场景4. 使用方法5. 完整代码示例5.1 事务类定义5.2 Driver 类定义5.3 Sequencer 类定义5.4 测试平台 6. 代码说明7. 总结 前言 以下是关于 UVM 中 uvm_driver 的详细解释、核心功能、适用场景、使用方法以及一个完整的代码示例ÿ…...
系统思考—双环学习
前几天,一个企业高管向我提到:“我们调整了N次方案,市场策略、团队激励、管理制度,能改的全改了,怎么还是不见起色?” 这让我想到典型的单环学习,简单来说就是:发现问题 → 采取行动…...
QTreeView和QTableView单元格添加超链接
QTreeView和QTableView单元格添加超链接的方法类似,本文仅以QTreeView为例。 在QTableView仿Excel表头排序和筛选中已经实现了超链接的添加,但是需要借助delegate,这里介绍一种更简单的方式,无需借助delegate。 一.效果 二.实现 QHTreeView.h #ifndef QHTREEVIEW_H #def…...
elastic search 的 highlight
Elasticsearch 的 highlight 功能用于在搜索结果中突出显示匹配的文本片段。这对于用户界面上的搜索结果展示非常有用,因为它可以帮助用户快速定位到他们搜索的关键词。 1. 基本用法 在 Elasticsearch 中,highlight 功能通常在查询中使用,并…...
【MySQL篇】行格式详解
MySQL行格式详解 文章目录 MySQL行格式详解🎉 什么是行格式🐱👤 如何查看行格式🐱🚀 InnoDB 行格式有哪些?🐱🏍 Compact 行格式🚩 额外信息🚀 变长字段…...
嵌入式知识点总结 操作系统 专题提升(五)-内存
针对于嵌入式软件杂乱的知识点总结起来,提供给读者学习复习对下述内容的强化。 目录 1.在1G内存的计算机能否malloc(1.2G)?为什么? 2.malloc能申请多大的空间? 3.内存管理有哪几种方式? 4.什…...
动手学深度学习---深层神经网络
目录 一、神经网络1.1、模型训练1.2、损失函数1.2.1、分类:hinge loss/合页损失/支持向量机损失1.2.2、分类:交叉熵损失(softmax分类器)1.2.2.1 二分类交叉熵损失1.2.2.2 多分类交叉熵损失 1.2.3、回归:误差平方和(SSE)…...
第9章 城市基础设施更新工程 9.1 道路改造施工
9.1 道路改造施工 9.1.1 道路改造施工内容 沥青、水泥混凝土、砌块路面及人行步道、绿化照明、附属设施、交通标志。沥青路面材料的再生利用。 9.1.2 道路改造施工技术 1.沥青路面病害及微表处理 1.病害处理 裂缝处理 10mm以内 专用灌缝材料、热沥青灌缝、缝内潮湿时采用…...
java基础6(黑马)
一、static 1.static修饰成员变量 static:叫静态,可以修饰成员变量、成员方法。 成员变量按照有无static,分两种。 类变量:有static修饰,属于类,在计算机中只有一份,会被类的全部对象共享。…...
Transformer 详解:了解 GPT、BERT 和 T5 背后的模型
目录 什么是 Transformer? Transformer如何工作? Transformer 为何有用? 常见问题解答:机器学习中的 Transformer 在技术领域,突破通常来自于修复损坏的东西。制造第一架飞机的人研究过鸟类。莱特兄弟观察了秃鹫如何在气流中保持平衡,意识到稳定性比动力更重要。…...
Ollama命令使用指南
Ollama 命令使用指南 Ollama 命令使用指南1. Ollama 命令概览2. Ollama 命令详解2.1 启动 Ollama2.2 创建模型2.3 查看模型信息2.4 运行模型2.5 停止运行的模型2.6 从注册表拉取模型2.7 推送模型到注册表2.8 列出本地模型2.9 查看正在运行的模型2.10 复制模型2.11 删除模型 3. …...
【Prometheus】MySQL主从搭建,以及如何通过prometheus监控MySQL运行状态
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
上传文件防木马函数
项目环境:TP6、TP5 问题:解决旧项目中上传上来的文件校验不严格。导致会有木马文件入侵的情况发生。除了上篇博文中提及的限制上传文件存储的目录不可执行php文件外。仍需在入口处严格检验上传文件的类型,排除php类可执行文件上传。 解决&a…...
百问网imx6ullpro调试记录(linux+qt)
调试记录 文章目录 调试记录进展1.开发板相关1.1百问网乌班图密码 1.2 换设备开发环境搭建串口调试网络互通nfs文件系统挂载 1.3网络问题1.4系统启动1.5进程操作 2.QT2.1tslib1.获取源码2.安装依赖文件3.编译 2.2qt移植1.获取qt源码2.配置编译器3.编译 2.3拷贝到开发板1.拷贝2.…...
人脸识别与人脸检测技术
人脸识别技术,作为一种基于人的脸部特征信息进行身份识别的生物识别技术,近年来在人工智能和计算机视觉技术的推动下取得了显著进展。它利用摄像机或摄像头采集含有人脸的图像或视频流,自动在图像中检测和跟踪人脸,进而对检测到的人脸进行一系列计算和分别判断。这一技术不…...
前端性能分析常见内容
前端性能分析是前端开发中的重要部分,以下是对前端常考性能分析题目的详解: 一、性能指标 前端性能优化的核心目标是提升用户体验,常见的性能指标包括: 加载时间(Load Time):指从用户发出请求…...
ZEMAX POPD操作数
在Zemax中,POPD(Physical Optics Propagation Data) 是一个用于物理光学传播(POP)分析的关键操作数,主要用于优化或分析光束的物理特性(如束腰、发散角、M因子等)。以下是对其使用方…...
ansible使用学习
一、查询手册 1、官网 ansible官网地址:https://docs.ansible.com 模块查看路径:https://docs.ansible.com/ansible/latest/collections/ansible/builtin/index.html#plugins-in-ansible-builtin 2、命令 ansible-doc -s command二、相关脚本 1、服务…...
VS2022中cmath.h头文件功能介绍
在C语言的世界里,数学运算一直是程序开发中不可或缺的一部分。无论是进行简单的数值计算,还是处理复杂的科学工程问题,都需要借助数学函数来实现。在Visual Studio 2022(VS2022)中,cmath.h(在C语…...
基于 PyTorch 的树叶分类任务:从数据准备到模型训练与测试
基于 PyTorch 的树叶分类任务:从数据准备到模型训练与测试 1. 引言 在计算机视觉领域,图像分类是一个经典的任务。本文将详细介绍如何使用 PyTorch 实现一个树叶分类任务。我们将从数据准备开始,逐步构建模型、训练模型,并在测试…...

