多重背包问题(基础+优化)

有 NN 种物品和一个容量是 VV 的背包。

第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。

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

输入格式

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

接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。

输出格式

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

数据范围

0<N≤10000<N≤1000
0<V≤20000<V≤2000
0<vi,wi,si≤20000<vi,wi,si≤2000

提示:

本题考查多重背包的二进制优化方法。

输入样例

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

输出样例:

 

10


题解

/**
 * 和完全背包问题类似,需要多加一层循环控制同一种物品的数量,时间复杂读较高
 * 我们主要学习下面优化多重背包问题如何转化为0-1背包问题
 */
import java.util.Scanner;

public class test7 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n=sc.nextInt();//物品种类数量
        int m=sc.nextInt();//背包大小
        int []bog=new int[m+2];
        for (int i=1;i<=n;i++){
             int vol=sc.nextInt();
             int val=sc.nextInt();
             int num=sc.nextInt();
             for (int j=m;j>0;j--){
                 for (int k=0;k<=j/vol&&k<=num;k++){//控制同一种物品的数量
                     bog[j]=Math.max(bog[j],bog[j-k*vol]+k*val);
                 }
             }
        }
        System.out.println(bog[m]);

    }
}

二进制优化  多重背包转化为0-1背包问题

/**
 * 我们先来看一个例子:
 * 一个数字,我们可以按照二进制来分解为1 + 2 + 4 + 8 …… +2^n + 余数
 * 十进制数字7,可以从二进制 100, 010,001 => 4、2、1  用1、2、4可以表示1~7中任意一个数。
 * 再比如,10,可以分为1,2,4,3---3就是余数!
 *
 * 通过上述原理,我们可以把第i件物品的s件,按二进制思想分为1,2,4…到剩余。
 * 再代码中控制每件物品取与不取就可以遍历1-i的所以数量的同一个物品,多重背包问题就变成0-1背包问题
 * 这样从复杂度为s,降到了(log2S)。最后的复杂度为O(V*Σlog n[i]),这样就快了许多!
 */
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

class things{
    int vol,val;
    public things(int vol, int val) {
        this.vol = vol;
        this.val = val;
    }
}
public class test8 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n=sc.nextInt(),m=sc.nextInt();
        int bog[]=new int[m+1];
        Queue<things> queue=new LinkedList<things>();
        for (int i=1;i<=n;i++){//转化为0-1背包问题
            int vol=sc.nextInt();
            int val=sc.nextInt();
            int num=sc.nextInt();
            //下面是把1-i数量的同一个物品按二进制思想分为1,2,4…到剩余,转化为0-1背包问题
            for (int k=1;k<=num;k=k*2){
                num=num-k;
                queue.offer(new things(k*vol,k*val));
            }
            if(num>0){
                queue.add(new things(num*vol,num*val));
            }
        }
        for (things things : queue) {
            for (int j=m;j>=things.vol;j--){
                bog[j]=Math.max(bog[j],bog[j-things.vol]+things.val);
            }
        }
        System.out.println(bog[m]);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

3Cloudream

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

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

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

打赏作者

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

抵扣说明:

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

余额充值