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

代码随想录day32:动态规划part5

完全背包

二维

/* 完全背包:动态规划 */
int unboundedKnapsackDP(int[] wgt, int[] val, int cap) {int n = wgt.length;// 初始化 dp 表int[][] dp = new int[n + 1][cap + 1];// 状态转移for (int i = 1; i <= n; i++) {for (int c = 1; c <= cap; c++) {if (wgt[i - 1] > c) {// 若超过背包容量,则不选物品 idp[i][c] = dp[i - 1][c];} else {// 不选和选物品 i 这两种方案的较大值dp[i][c] = Math.max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + val[i - 1]);}}}return dp[n][cap];
}

一维

/* 完全背包:空间优化后的动态规划 */
int unboundedKnapsackDPComp(int[] wgt, int[] val, int cap) {int n = wgt.length;// 初始化 dp 表int[] dp = new int[cap + 1];// 状态转移for (int i = 1; i <= n; i++) {for (int c = 1; c <= cap; c++) {if (wgt[i - 1] > c) {// 若超过背包容量,则不选物品 idp[c] = dp[c];} else {// 不选和选物品 i 这两种方案的较大值dp[c] = Math.max(dp[c], dp[c - wgt[i - 1]] + val[i - 1]);}}}return dp[cap];
}

由于当前状态是从左边和上边的状态转移而来的,因此空间优化后应该对 dp 表中的每一行进行正序遍历

这个遍历顺序与 0-1 背包正好相反。hello算法讲解的很清楚。

518. 零钱兑换 II

class Solution {public int change(int amount, int[] coins) {int[] dp = new int[amount + 1];dp[0] = 1;for(int i = 1; i <= coins.length; i++){for(int j = 0; j <= amount; j++){if(coins[i - 1] > j){dp[j] = dp[j];}else{dp[j] = dp[j] + dp[j - coins[i - 1]];}}}return dp[amount];}
}
零钱换整1

就是完全背包min问题,初始化最上边一行为max = amount + 1用与比较

零钱换整2 

就是方案问题,

二维方案问题

    for (int i = 0; i <= n; i++) {dp[i][0] = 1;}

“在前0个数字中,凑出和为0的组合,有几种方法”,我们只能选择放弃“第0个数字”

一维就dp[0] = 1;就行,其实一维的好写,不用考虑遍历边界。

状态转移跟494. 目标和第一个做的方案问题一样,改成完全背包的形式,正序遍历。

377. 组合总和 Ⅳ

class Solution {public int combinationSum4(int[] nums, int target) {int[] dp = new int[target + 1];dp[0] = 1;for(int j = 0; j <= target; j++){for(int i = 1; i <= nums.length; i++){if(j - nums[i - 1] >= 0){dp[j] = dp[j] + dp[j - nums[i - 1]];}}}return dp[target];}
}

跟上一题的区别就是上一题是组合问题,这次是排列问题。

第一种遍历顺序(组合数)
for (int i = 0; i < coins.size(); i++) { // 遍历物品for (int j = coins[i]; j <= amount; j++) { // 遍历背包容量dp[j] += dp[j - coins[i]];}
}
  • 分析:
    • 外层循环遍历每种硬币。在计算时,内层循环从当前硬币的面额开始,更新所有可能的金额。
    • 这种方式确保了对于每种硬币,只能在其面额之后进行更新,导致 dp 数组中只计算组合,避免重复计数。
第二种遍历顺序(排列数)
for (int j = 0; j <= amount; j++) { // 遍历背包容量for (int i = 0; i < coins.size(); i++) { // 遍历物品if (j - coins[i] >= 0) dp[j] += dp[j - coins[i]];}
}
  • 分析:
    • 外层循环遍历每个可能的金额,内层循环遍历每种硬币。
    • 在这种顺序下,每个金额 j 都会考虑每种硬币的组合,导致 dp[j] 中包含了所有可能的排列。
  • 如果求组合数就是外层for循环遍历物品,内层for遍历背包。

    如果求排列数就是外层for遍历背包,内层for循环遍历物品。

70. 爬楼梯(进阶版)

改为:一步一个台阶,两个台阶,三个台阶,.......,直到 m个台阶。问有多少种不同的方法可以爬到楼顶呢?

这又有难度了,这其实是一个完全背包问题。

1阶,2阶,.... m阶就是物品,楼顶就是背包。

每一阶可以重复使用,例如跳了1阶,还可以继续跳1阶。

问跳到楼顶有几种方法其实就是问装满背包有几种方法。

import java.util.Scanner;
class climbStairs{public static void main(String [] args){Scanner sc = new Scanner(System.in);int m, n;while (sc.hasNextInt()) {// 从键盘输入参数,中间用空格隔开n = sc.nextInt();m = sc.nextInt();// 求排列问题,先遍历背包再遍历物品int[] dp = new int[n + 1];dp[0] = 1;for (int j = 1; j <= n; j++) {for (int i = 1; i <= m; i++) {if (j - i >= 0) dp[j] += dp[j - i];}}System.out.println(dp[n]);}}
}


http://www.mrgr.cn/news/48145.html

相关文章:

  • 数据库系统概论
  • redis数据类型:list
  • Qemu 加载你指定的 initrd、dtb 到哪里?
  • 【环境搭建】Python、PyTorch与cuda的版本对应表
  • 第5章:基于EfficientNet 网络实现的图像分类任务:104种花种类识别
  • QEMU安装使用@FreeBSD
  • 每天一题:洛谷P1279 字串距离
  • 解决使用MobaXterm不能向Ubuntu上传下载文件的问题
  • 推荐阅读:丰田汽车金融支老师使用“数智化审计赋能平台”之体验分享
  • DM原生JDBC,查询结果用Jackson序列化,字段为TEXT类型且存的json字符串时,报错“Infinite recursion“
  • HCIP--以太网交换安全(二)端口安全
  • RDD优化:缓存和checkpoint机制、数据共享(广播变量、累加器)、RDD的依赖关系、shuffle过程、并行度说明
  • Git介绍--github/gitee/gitlab使用
  • Qt 数据库,人脸识别
  • Matplotlib库
  • 6个设计师都在用的样机素材网站
  • 400行程序写一个实时操作系统RTOS(开篇)
  • Flutter技术学习
  • 大数据新视界 --大数据大厂之 ClickHouse:大数据分析领域的璀璨明星
  • ☕️从小工到专家的 Java 进阶之旅:全新的HttpClient,现代高效的网络通信利器
  • 每日OJ题_牛客_小乐乐改数字_模拟_C++_Java
  • 算法的收敛速度计算过程
  • 『网络游戏』进入游戏主城UI跳转主城【26】
  • Linux下的Makefile基本操作
  • Redis 的安装与部署(图文)
  • 中间件:SpringBoot集成Redis