有 N种物品和一个容量是 V的背包。
物品一共有三类:
第一类物品只能用1次(01背包);
第二类物品可以用无限次(完全背包);
第三类物品最多只能用 si次(多重背包);
每种体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式:
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
si=−1 表示第 i 种物品只能用1次;
si=0 表示第 i 种物品可以用无限次;
si>0 表示第 i 种物品可以使用 si 次;
输出格式:
输出一个整数,表示最大价值。
数据范围:
0<N,V≤1000
0<vi,wi≤1000
−1≤si≤1000
将01背包和完全背包转换为多重背包,再将多重背包进行二进制优化转换为01背包解决。
在本一道题当中,我们可以看到若此题为多重背包问题,那么按照数据范围来看,其实可以用多重背包问题的二进制优化方法来水过,先将01背包,完全背包转化成多重背包,01背包的话,则可以将物品数量写成1,而完全背包,则数量为(总体积(V)/该物品的体积(v[i])。再按照多重背包的思路,即将多重背包转化成一个个的二进制01背包来做即可。
代码如下:
import java.util.Scanner;
public class Main{
public static void main(String[] args){
int N,V;
Scanner scan=new Scanner(System.in);
N=scan.nextInt();
V=scan.nextInt();
int[] dp=new int[V+1];
for(int i=0;i<N;i++){
int k=1;//多重背包优化的分组数
int w=scan.nextInt();
int v=scan.nextInt();
int s=scan.nextInt();
if(s<0)//01背包转换为多重背包
{
s=1;
}
else if(s==0)//完全背包转换为多重背包
{
s=V/w;
}
//多重背包的二进制优化
while(s>0){
if(s-k<0){
for(int j=V;j>=s*w;j--){
dp[j]=Math.max(dp[j],dp[j-s*w]+s*v);
}
break;
}
for(int j=V;j>=k*w;j--){
dp[j]=Math.max(dp[j],dp[j-k*w]+k*v);
}
s-=k;
k*=2;
}
}
System.out.println(dp[V]);
}
}