动态规划:多重背包问题II


往期

  1. 01背包问题
  2. 完全背包问题
  3. 多重背包问题I

题目

多重背包问题II
N N N 种物品和一个容量是 V V V 的背包。

i i i 种物品最多有 s i s_{i} si 件,每件体积是 v i v_{i} vi,价值是 w i w_{i} wi

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入格式
第一行两个整数, N N N V V V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N N N 行,每行三个整数 v i v_{i} vi, w i w_{i} wi, s i s_{i} si,用空格隔开,分别表示第 i i i 种物品的体积、价值和数量。

输出格式
输出一个整数,表示最大价值。

数据范围
0 < N ≤ 1000 0< N\le 1000 0<N1000
0 < V ≤ 2000 0< V\le 2000 0<V2000
0 < v i , w i , s i ≤ 2000 0< v_{i},w_{i},s_{i}\le 2000 0<vi,wi,si2000

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例

10

解题思路

相比多重背包问题I,本题数据范围变大,需优化时间复杂度

不能用完全背包问题抛弃k循环的思路来优化这个问题,因为每个物品的件数不同,不能像完全背包问题那样优化状态转移方程

多重背包的二进制优化

考虑将多重背包问题转化为01背包问题,考虑把第 i i i种物品换成若干件物品,使得原问题中第 i i i种物品可取的每种策略(取 0 0 0件、取 1 1 1件、…、取 k k k件),均能等价于取若干件转换以后的物品,取超过 k k k件的策略必不能出现

若直接把第 i i i件物品换成 s [ i ] s[i] s[i]件01背包中的物品,时间复杂度不变。

考虑二进制的思想,将 k k k件物品拆成 log ⁡ 2 k \log_{2}{k} log2k件新的物品, k = 1 + 2 + 2 2 + . . . + 2 t + c ( c ≤ 2 t + 1 ) k=1+2+2^{2}+...+2^{t}+c\left ( c\le 2^{t+1} \right ) k=1+2+22+...+2t+c(c2t+1)用这 log ⁡ 2 k \log_{2}{k} log2k个新数,可以凑出 0 ∼ k 0 \sim k 0k中的任何一个数。这 log ⁡ 2 k \log_{2}{k} log2k个数作为新物品的系数,新物品的体积和价值就是原物品的费用和价值乘以这个系数。

eg: 13 = 1 + 2 + 4 + 6 13=1+2+4+6 13=1+2+4+6,最多取13件的物品被分成系数分别为 1 , 2 , 4 , 6 1,2,4,6 1,2,4,6的四件物品,原先要枚举14次,拆分之后只需枚举5次;这种优化对于大数尤其明显,例如最多取1024件的物品,在正常情况下要枚举1025次 , 二进制思想下转化成01背包只需要枚举11次。

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int n = sc.nextInt();               // 物品种数
        int m = sc.nextInt();               // 背包容积
        
        int[] v = new int[n];
        int[] w = new int[n];
        int[] s = new int[n];
        
        
        for (int i = 0; i < n; i++) {
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
            s[i] = sc.nextInt();
        }
        
        // 二进制拆分
        int[] newV = new int[n*11];    // 2^11 = 2048,也就是说s最多可以拆成11个,故数组容量乘以11
        int[] newW = new int[n*11];
        int newN = 0;                   // 新的物品种数
        for (int i = 0; i < n; i++) {
            for (int j = 1; j <= s[i]; j *= 2) {
                newV[newN] = j * v[i];   // 体积
                newW[newN] = j * w[i];   // 价值
                s[i] -= j;
                newN++;
            }
            if (s[i] > 0) {
                newV[newN] = s[i] * v[i];
                newW[newN] = s[i] * w[i];
                newN++;
            }
        }
        
        // 01背包问题
        int[] dp = new int[m+1];        
        for (int i = 0; i < newN; i++) {
            for (int j = m; j >= newV[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j-newV[i]]+newW[i]);
            }
        }
        System.out.println(dp[m]);
    }
}

Reference

  1. 背包问题九讲
  2. 多重背包的二进制拆分代码
  3. 多重背包问题的优化思路
  4. 多重背包问题的优化思路
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
多重背包问题是指在一定的背包容量下,有多个物品的重量和价值,每个物品有一定的数量限制,要求在放入背包时,使得背包中物品的总价值最大化。动态规划是解决多重背包问题的一种常见方法。 其中,引用提供了一种将多重背包问题转化为01背包问题的方法。这种方法将每个多重背包问题的物品按照其数量进行拆分,使其变成多个01背包问题。然后使用动态规划的思想,依次求解每个01背包问题,最终得到多重背包问题的最优解。 引用提供了一种对完全背包问题的暴力解法做简单修改的方法。该方法同样使用动态规划的思想,对每个物品进行遍历,并在背包承重为j的前提下,求解每个物品能放入的最大数量。然后根据物品的重量和价值进行计算,得到多重背包问题的最优解。 这两种方法都可以用来解决多重背包问题,并根据实际情况选择合适的方法进行求解。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [动态规划(五):多重背包问题](https://blog.csdn.net/qq_42138662/article/details/118434151)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [动态规划多重背包问题](https://blog.csdn.net/qq_42174306/article/details/124345411)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [动态规划4:多重背包](https://blog.csdn.net/qq_40772692/article/details/81435230)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xylitolz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值