小明的背包——多重背包

题目链接:3.小明的背包3 - 蓝桥云课 (lanqiao.cn)

多重背包基础模型

这里的每一种物品只有s+1种状态,即“拿0个,1个……s个”。在基础版模型中,多重背包就是将每个物品的s个摊开,变为s种不同的物品,从而退化成01背包处理。

只需要在01背包的基础上稍加改动,对每一个物品循环更新s次即可。

01背包问题:小明的背包——01背包问题-CSDN博客

package lanqiao;

import java.util.Scanner;

/**
 * 2024/3/13
 * 多重背包
 */
public class lanqiao1176_小明的背包3 {
    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        int N=scan.nextInt();//物品种类
        int V=scan.nextInt();//背包容量
        int[] w=new int[N];//体积
        int[] v=new int[N];//价值
        int[] s=new int[N];//个数
        for (int i=0;i<N;i++){
            w[i]=scan.nextInt();
            v[i]=scan.nextInt();
            s[i]=scan.nextInt();
        }
        int[][] dp=new int[N+1][V+1];
        for (int i=1;i<=N;i++){//种类
            for (int j=1;j<=V;j++){//体积
                for (int k=0;k<=Math.min(s[i-1],j/w[i-1]);k++){//每个物品的个数,查找最大值(k要小于物品所剩个数和此时背包能装下这个物品的个数的最小值)
                        dp[i][j]=Math.max(dp[i][j],dp[i-1][j-w[i-1]*k]+k*v[i-1]);//个数一个一个地增加
                }
            }
        }
        System.out.println("最大价值为:"+dp[N][V]);
    }
}
3 30
1 2 3
4 5 6
7 8 9
最大价值为:39

进程已结束,退出代码为 0

二进制优化模型

多重背包基础模型的时间复杂度为O(n*s*V),当s比较大时,容易超时。

为了解决这个问题,可以在“拆分”过程中进行优化,不在拆分成均为一个物品的组,二十每一组的个数为1、2、4、8……,最后剩下的单独一组,这样一定存在一种方案来表示0~s的所有情况(二进制的表示方法)

在此模型中,一种物品被拆分约为log2(s)组,例如s=11=1+2+4+4

这样拆分后的物品跑一边01背包即可,时间复杂度为O(n*log(s)*V)。

package lanqiao;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * 2024/3/13
 * 多重背包
 * 容量为V,物品种类N,第i件物品体积为wi,价值为vi,数量为si
 * 求最大价值
 */
public class lanqiao1176_小明的背包3 {
    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        int N=scan.nextInt();//物品个数
        int V=scan.nextInt();//背包体积
        int[] w=new int[N];//体积
        int[] v=new int[N];//价值
        int[] s=new int[N];//数量
        List<Integer> a=new ArrayList<>();//存放二进制分组后的体积
        List<Integer> b=new ArrayList<>();//存放二进制分组后的价值
        for (int i=0;i<N;i++){
            w[i]=scan.nextInt();
            v[i]=scan.nextInt();
            s[i]=scan.nextInt();
            for (int k=1;k<=s[i];k*=2){//进行二进制分组,每组个数分别1、2、4、8……
                a.add(w[i]*k);
                b.add(v[i]*k);
                s[i]-=k;
            }
            if (s[i]>0){//如果二进制分组后有剩余,就放在一起
                a.add(w[i]*s[i]);
                b.add(v[i]*s[i]);
            }
        }
        int[] dp=new int[V+1];
        for (int i=0;i<a.size();i++){//与01背包近似
            int w1=a.get(i);
            int v1=b.get(i);
            for (int j=V;j>=w1;j--){
                dp[j]=Math.max(dp[j],dp[j-w1]+v1);
            }
        }
        System.out.println("最大价值为:"+dp[V]);
    }
}
3 30
1 2 3
4 5 6
7 8 9
最大价值为:39

进程已结束,退出代码为 0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值