目录
- 01背包 二维写法
- 01背包 一维写法
- 完全背包 二维 带枚举写法
- 完全背包 二维 普通写法
- 完全背包 一维写法
- 多重背包 二维写法
- 多重背包 一维写法
- 多重背包 一维写法二进制优化
1. 01背包 二维写法
- dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - w[i - 1]] + v[i - 1])
1 2 3 4 5 6 7 8 9 10 11 12 | // 填写动态规划表 for ( int i = 1 ; i <= n; i++) { for ( int j = 1 ; j <= C; j++) { if (j < w[i - 1 ]) { // 第i种物品的重量大于当前背包的剩余容量,不能放入 dp[i][j] = dp[i - 1 ][j]; } else { // 第i种物品的重量小于等于当前背包的剩余容量,可以选择放入或不放入 dp[i][j] = Math.max(dp[i - 1 ][j], dp[i - 1 ][j - w[i - 1 ]] + v[i - 1 ]); } } } |
2. 01背包 一维写法
- dp[j] = Math.max(dp[j], dp[j - w[i - 1]] + v[i - 1]) 注:j逆序
1 2 3 4 5 6 7 | for ( int i = 1 ; i <= N; i++) { for ( int j = C; j >= 0 ; j--) { if (j >= w[i - 1 ]) { dp[j] = Math.max(dp[j], dp[j - w[i - 1 ]] + v[i - 1 ]); } } } |
3. 完全背包 二维 带枚举写法
- dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * v[i - 1]] + k * w[i - 1])
1 2 3 4 5 6 7 8 9 | // 状态转移 for ( int i = 1 ; i <= n; i++) { for ( int j = 1 ; j <= V; j++) { dp[i][j] = dp[i - 1 ][j]; // 不装第i种物品 for ( int k = 0 ; k * v[i - 1 ] <= j; k++) { // 枚举装k个第i种物品 dp[i][j] = Math.max(dp[i][j], dp[i - 1 ][j - k * v[i - 1 ]] + k * w[i - 1 ]); // 比较不装和装第i种物品的最大价值 } } } |
4. 完全背包 二维 普通写法
- dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - v[i - 1]] + w[i - 1])
1 2 3 4 5 | for ( int i = 1 ; i <= N; i++) { for ( int j = v[i - 1 ]; j <= C; j++) { dp[i][j] = Math.max(dp[i - 1 ][j], dp[i][j - v[i - 1 ]] + w[i - 1 ]); } } |
1 | <br><br> |
5. 完全背包 一维写法
- dp[j] = Math.max(dp[j], dp[j - v[i - 1]] + w[i - 1]) 注:j 顺序
1 2 3 4 5 | for ( int i = 1 ; i <= N; i++) { <strong> for ( int j = v[i - 1 ]; j <= C; j++) {</strong> dp[j] = Math.max(dp[j], dp[j - v[i - 1 ]] + w[i - 1 ]); } } |
注意
这里的 dp[j] = Math.max(dp[j], dp[j - v[i - 1]] + w[i - 1])
实际是 dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - v[i - 1]] + w[i - 1]) 的简化,
这里用到了 dp[i][j - v[i - 1]],也就是说 计算当前层 不止用到了上一层,还用到了本层比较小的容量,这就是为什么必须正序的原因
6. 多重背包 二维写法
- dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * v[i]] + k * w[i])
1 2 3 4 5 6 7 | for ( int i = 1 ; i <= N; i++) { // 遍历物品 for ( int j = 0 ; j <= V; j++) { // 遍历背包容量 for ( int k = 0 ; k <= s[i] && k * v[i] <= j; k++) { // 遍历物品数量 dp[i][j] = Math.max(dp[i][j], dp[i - 1 ][j - k * v[i]] + k * w[i]); // 状态转移 } } } |
7. 多重背包 一维写法
- dp[j] = Math.max(dp[j], dp[j - k * v[i - 1]] + k * w[i - 1])
1 2 3 4 5 6 7 | for ( int i = 1 ; i <= N; i++) { for ( int j = C; j >= v[i - 1 ]; j--) { for ( int k = 0 ; k <= s[i - 1 ] && k * v[i - 1 ] <= j; k++) { dp[j] = Math.max(dp[j], dp[j - k * v[i - 1 ]] + k * w[i - 1 ]); } } } |
8. 多重背包 一维写法二进制优化
- dp[j] = Math.max(dp[j], dp[j - k * v[i]] + k * w[i])
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | for ( int i = 1 ; i <= N; i++) { // 遍历物品 int k = 1 ; // 拆分因子 while (k <= s[i]) { // 拆分数量不超过原数量 for ( int j = V; j >= k * v[i]; j--) { // 遍历背包容量 dp[j] = Math.max(dp[j], dp[j - k * v[i]] + k * w[i]); // 状态转移 } s[i] -= k; // 减去已拆分的数量 k <<= 1 ; // 拆分因子翻倍 } if (s[i] > 0 ) { // 如果还有剩余数量 for ( int j = V; j >= s[i] * v[i]; j--) { // 遍历背包容量 dp[j] = Math.max(dp[j], dp[j - s[i] * v[i]] + s[i] * w[i]); // 状态转移 } } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
2021-07-08 使用Guava RateLimiter限流以及源码解析
2021-07-08 方法论-索引
2021-07-08 神器 | 根因分析法,教你成为解决问题的高手
2021-07-08 java.util.Objects.isNull vs object == null 之Objects类的介绍
2021-07-08 好用的java.util.Objects类
2021-07-08 java.util.Objects 简介
2021-07-08 Java的对象工具类Objects