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

算法训练营DAY37 第九章 动态规划 part05

完全背包理论基础-二维DP数组

完全背包

有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。

1. 确定dp数组以及下标的含义

dp[i][j] 表示从下标为[0-i]的物品,每个物品可以取无限次,放进容量为j的背包,价值总和最大是多少

2. 确定递推公式

重量价值
物品0115
物品1320
物品2430

 分析dp[1][4]的推导过程,需要对比:目前背包容量为4,如果空出物品1的重量3,剩余重量为1的背包的最大价值+物品一的价值dp[i][j - weight[i]] + value[i];目前背包容量为4,不装物品1,只装物品一之前的物品的最大价值dp[i - 1][j]。

所以递推公式为dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]);

3. dp数组初始化

首先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为0。

状态转移方程 dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]); 可以看出有一个方向 i 是由 i-1 推导出来,那么i为0的时候就一定要初始化。

dp[0][j],即:存放编号0的物品的时候,各个容量的背包所能存放的最大价值。 j < weight[0]的时候,dp[0][j] 应该是 0;当j >= weight[0]时,dp[0][j] 如果能放下weight[0]的话,就一直装,每一种物品有无限个

4. 确定遍历顺序

先物品后背包或者先背包后物品都是可以的。

5. 举例推导dp数组

#include <iostream>
#include <vector>
using namespace std;int main() {int n, bagWeight;int w, v;cin >> n >> bagWeight;vector<int> weight(n);vector<int> value(n);for (int i = 0; i < n; i++) {cin >> weight[i] >> value[i];}vector<vector<int>> dp(n, vector<int>(bagWeight + 1, 0));// 初始化for (int j = weight[0]; j <= bagWeight; j++)dp[0][j] = dp[0][j - weight[0]] + value[0];for (int i = 1; i < n; i++) { // 遍历物品for(int j = 0; j <= bagWeight; j++) { // 遍历背包容量if (j < weight[i]) dp[i][j] = dp[i - 1][j];else dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]);}}cout << dp[n - 1][bagWeight] << endl;return 0;
}

518.零钱兑换II

518. 零钱兑换 II - 力扣(LeetCode)

给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。

示例 1:

  • 输入: amount = 5, coins = [1, 2, 5]
  • 输出: 4

解释: 有四种方式可以凑成总金额:

  • 5=5
  • 5=2+2+1
  • 5=2+1+1+1
  • 5=1+1+1+1+1

1、确定dp数组以及下标的含义

dp[i][j]:使用 下标为[0, i]的coins[i]能够凑满j(包括j)这么大容量的包,有dp[i][j]种组合方法。

2、确定递推公式

本题递推公式:dp[i][j] = dp[i - 1][j] + dp[i][j - nums[i]]

dp[i][j]的计算方式等于:不加第i种硬币凑出j的数量+需要再加一个第i种硬币的数量,即

dp[i][j] = dp[i - 1][j] + dp[i][j - nums[i]]

3. dp数组如何初始化

二维数组的最上行 和 最左列一定要初始化,这是递推公式推导的基础,

dp[0][0]

应该是:背包空间为0,装满「物品0」 的组合数有多少呢?

应该是 0 个

dp[0][j] 

如果 j 可以整除 物品0,那么装满背包就有1种组合方法。

dp[i][0] 的含义:用物品i(即coins[i]) 装满容量为0的背包 有几种组合方法。

都有一种方法,即不装。

所以 dp[i][0] 都初始化为1

4. 确定遍历顺序

二维DP数组的完全背包的两个for循环先后顺序是无所谓的。

5. 打印DP数组

class Solution {
public:int change(int amount, vector<int>& coins) {int bagsize=amount;vector<vector<uint64_t>> dp(coins.size(),vector<uint64_t>(bagsize+1,0));for(int j=0;j<=bagsize;j++){if(j%coins[0]==0)dp[0][j]=1;}for(int i=0;i<coins.size();i++){dp[i][0]=1;}for(int i=1;i<coins.size();i++){for(int j=1;j<=bagsize;j++){if(coins[i]>j)dp[i][j]=dp[i-1][j];else{dp[i][j]=dp[i-1][j]+dp[i][j-coins[i]];}}}return dp[coins.size()-1][bagsize];}
}; 

377. 组合总和 Ⅳ

377. 组合总和 Ⅳ

class Solution {
public:int combinationSum4(vector<int>& nums, int target) {vector<int> dp(target + 1, 0);dp[0] = 1;for (int i = 0; i <= target; i++) { // 遍历背包for (int j = 0; j < nums.size(); j++) { // 遍历物品if (i - nums[j] >= 0 && dp[i] <= INT_MAX - dp[i - nums[j]]) {dp[i] += dp[i - nums[j]];}}}return dp[target];}
};

377. 组合总和 Ⅳ

给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。

示例:

  • nums = [1, 2, 3]
  • target = 4

所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1)

请注意,顺序不同的序列被视作不同的组合。

因此输出为 7。

动规五部曲分析

1、确定dp数组以及下标的含义

dp[i]: 凑成目标正整数为i的排列个数为dp[i]

2、确定递推公式

dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导出来。

dp[i] += dp[i - nums[j]];

3、dp数组初始化

因为递推公式dp[i] += dp[i - nums[j]]的缘故,dp[0]要初始化为1。非0下标的dp[i]应该初始为0,这样才不会影响dp[i]累加所有的dp[i - nums[j]]。

4、确定遍历顺序

数字不限制使用次数,完全背包

得到的集合是排列,所以要考虑元素之间的顺序。

组合数:外层物品内层背包

排列数:外层背包,内层物品

5、距离推导

70. 爬楼梯(进阶版)

卡码网:57. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

输入描述:输入共一行,包含两个正整数,分别表示n, m

输出描述:输出一个整数,表示爬到楼顶的方法数。

输入示例:3 2

输出示例:3

提示:

当 m = 2,n = 3 时,n = 3 这表示一共有三个台阶,m = 2 代表你每次可以爬一个台阶或者两个台阶。

此时你有三种方法可以爬到楼顶。

  • 1 阶 + 1 阶 + 1 阶段
  • 1 阶 + 2 阶
  • 2 阶 + 1 

动规五部曲

1、确定dp数组以及下标的含义

dp[i]:爬到有i个台阶的楼顶,有dp[i]种方法

2、确定递推公式

dp[i] += dp[i - j]

3、dp数组初始化

dp[0] 一定为1,下标非0的dp[i]初始化为0。

4、确定遍历顺序

答案是要求排列,所以外层循环背包target;内层循环nums物品;

5、举例推导

#include <iostream>
#include <vector>
using namespace std;
int main(){int n,m;while(cin>>n>>m){vector<int> dp(n+1,0);dp[0]=1;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(i-j>=0){dp[i]+=dp[i-j];}}}cout<<dp[n]<<endl;}
}

http://www.lryc.cn/news/595120.html

相关文章:

  • 两个相机的视野 拼接算法
  • 【C++】stack和queue拓展学习
  • DevCon 6记录
  • 从 “能用“ 到 “好用“:中小制造企业数字化转型中的 IT 系统优化管理策略
  • 扬声器测试解决方案
  • AWS Certified Cloud Practitioner 认证考试总结
  • Centos安装最新docker以及ubuntu安装docker
  • 旋转目标检测(Rotated Object Detection)技术概述
  • ESP32-S3学习笔记<1>:ESP-IDF的安装与命令
  • 【编程语言】C、C++、C#深度对比:三种语言的演进历程与应用场景
  • Windows VS2019 编译 Apache Thrift 0.15.0
  • 倒排索引实操
  • CS231n-2017 Lecture4神经网络笔记
  • selenium爬取图书信息
  • 通信刚需小能手,devicenet转PROFINET网关兼容物流分拣自动化
  • 从cv610的demo原理看,i2c的上拉电阻为 1k
  • day27 力扣332.重新安排行程 力扣51. N皇后 力扣37. 解数独 力扣455.分发饼干 力扣376. 摆动序列 力扣53. 最大子序和
  • 【设计模式C#】工厂方法模式(相比简单工厂模式更加具有灵活性和扩展性的工厂模式)
  • 力扣15:三数之和
  • 测量误差溯源:系统误差与随机误差的数学建模与分离方法
  • 结构型模式-架构解耦与扩展实践
  • 清理磁盘空间
  • Windows容器网络的带宽限制QoS策略配置
  • CPO光模块能取代传统光模块吗?
  • 量子算法可视化工具:撕裂量子黑箱的破壁者
  • 量子生成对抗网络:量子计算与生成模型的融合革命
  • 云原生安全工具:数字基础设施的免疫长城
  • 苹果Find My新增智能位置共享模式​​
  • 自动化计算机经过加固后有什么好处?
  • Android开发中ANR治理方案