题目链接: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