多重背包问题朴素解法+二进制优化

多重背包问题

每个物品可以选择的次数是不同的,有限制的

题目来源
在这里插入图片描述

一维数组朴素解法

import java.util.Scanner;
//多重背包问题
public class Main {
    //每一个物品有物品数量的限制

    /**
     * 多重背包
     * f[v] 表示 体积是v的时候背包的最大价值
     * 所有的都是0 f[v] 就是答案
     * f[0] 是0 其他是负无穷  就是 从 f[0] - f[v]找最大值
     * @param args
     */
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int V = sc.nextInt();
        int[] v = new int[N+1];
        int[] w= new int[N+1];
        int[] l = new int[N+1];
        for(int i = 1 ;i <= N;i++){
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
            l[i] = sc.nextInt();
        }

        int[] f = new int[V+1];
        for(int i = 1 ;i <= N;i++){
            //这里必须是从大到小 枚举保证没有计算过
            //而完全背包问题 之所以可以是用从小到大枚举是 没有k这个循环在里面的
            for(int j = V;j >= v[i];j--){
                f[j] = f[j];
                //枚举选择的个数
                for(int k = 1 ;k <= l[i] && k* v[i] <= j;k++){
                    f[j] = Math.max(f[j],f[j-k*v[i]]+k*w[i]);
                }
            }
        }

        System.out.println(f[V]);
    }

}

题目来源
区别就是数据规模变大,如果继续使用上述解法可能会出现超时的情况
在这里插入图片描述

一维数组二进制优化解法
上述做法分析:三重循环 时间复杂度太大
可以使用多重背包的二进制优化方法
把某一个物品对应的数字s用二进制的写法表示出
s=1+2+4+…+2^k+c,就是通过二进制优化进行转换。
在这里插入图片描述
注意最后一个数字可能需要重新考虑计算
在这里插入图片描述

import java.util.*;
public class Main{
    static class  Good{
        int V;
        int W;

        public Good(int v, int w) {
            V = v;
            W = w;
        }

        public int getV() {
            return V;
        }

        public int getW() {
            return W;
        }
    }

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int V = sc.nextInt();
        int[] v = new int[N+1];
        int[] w= new int[N+1];
        int[] l = new int[N+1];
        for(int i = 1 ;i <= N;i++){
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
            l[i] = sc.nextInt();//物品数量的限制
        }
        int[] f = new int[V+1];
        Deque<Good> deque = new LinkedList<>();

        //然后处理每一个物品对应的个数 把他拆成一个0-1背包的问题
        //转换成很多物品的体积价值的关系
        // 转换成不同的物品 对应不同的体积和价值
        for(int i = 1;i<= N;i++){
            //得到每一个物品的个数
            int num = l[i];
            //处理这里处理数据的方式
            for(int k = 1;k <= num;k*=2){
                num -= k;
                deque.push(new Good(k*v[i],k*w[i]));
            }
            if(num >0) deque.push(new Good(num*v[i],num*w[i]));
        }

        //0-1背包 枚举每一个物品 注意物品的数量变了!
        N = deque.size();
        for(int i = 0; i < N;i++){
            //然后从大到小枚举体积
            Good temp = deque.pop();
            for(int j = V; j >=temp.getV();j--){
                f[j] = Math.max(f[j],f[j-temp.getV()]+temp.getW());
            }
        }
        System.out.println(f[V]);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值