多重背包问题
每个物品可以选择的次数是不同的,有限制的
一维数组朴素解法
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]);
}
}