题目
有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。
完全背包和01背包问题唯一不同的地方就是,每种物品有无限件。
例子:
背包最大重量为4。
物品为:
每件商品都有无限个!问背包能背的物品最大价值是多少?
思路
01背包和完全背包的唯一不同就是体现在遍历顺序上
以下是01背包的核心代码:
for(int i = 0; i < weight.length; i++){// 遍历物品
for(int j = bagsize; j >= weight[i]; j--){// 反向遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
其中01背包中内部循环是从大到小遍历,为了保证每个物品被添加一次;
而完全背包的物品是可以添加多次的,所以要从小到大去遍历
for(int i = 0; i < weight.length; i++){//遍历物品
for(int j = weight[i] ; j <= bagsize; j++){// 正向遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
另外需要注意的是,在01背包中,二维dp数组的两个for循环遍历先后顺序可以颠倒,但是01背包的一维dp数组的两个for循环一定是先遍历物品,再遍历背包容量
而在完全背包中,对于一维dp数组来说,两个for循环顺序无所谓,都不影响计算dp[j]
所需要的值(这个值就是下标j之前所对应的dp[j]
)
这里只针对纯完全背包问题(两个for循环先后顺序可以颠倒),但是如果题目有变化,就会体现在遍历顺序上了
java代码如下:
//先遍历物品,再遍历背包
public static void testCompletePack(){
int[] weight = {1,3,4};
int[] value = {15,20,30};
int bagsize = 4;
int[] dp new int[bagsize+1];
for(int i = 0; i < weight.length; i++){//遍历物品
for(int j = weight[i]; j <= bagsize; j++){//正序遍历(因为一个物品可以重复添加多次),遍历背包容量
dp[j] = Math.max(dp[j], dp[j - weight[i]] + values[i]);
}
}
for(int maxValue : dp){
System.out.println(maxValue + " ");
}
}
//先遍历背包,再遍历物品
public static void testCompletePack1(){
int[] weight = {1,3,4};
int[] value = {15,20,30};
int bagsize = 4;
int[] dp new int[bagsize+1];
for(int i = 1; i <= bagsize; i++){//遍历背包容量
for(int j = 0; j < weight.length ; j++){//正序遍历物品
if( i - weight[j] >= 0){
dp[i] = Math.max(dp[i], dp[i - weight[j]] + value[j]);
}
}
}
for(int maxValue : dp){
System.out.println(maxValue + " ");
}
}