问题描述:
给定N个物品,并且给出他们的价值和重量。给一个承重最多为WW袋子,问用这个袋子装物品,能得到的最大价值是多少?
解题思路:
这个和01背包问题最大的区别在于每一种物品可以选择多个。建立dp表,行表示当前最大容量,列表示当前的可选范围。每一个单元格表示在当前最大容量以及可选范围内可以得到的最大价值。我们可以首先对第一行和第一列进行初始化,第一列也就是最大容量是0时能获得的最大价值肯定也是0;第一行也就是只有0个物品可以选时,最大价值肯定是这个物品价值的倍数,拿当前容量除以物品的重量取整然后乘以物品的重量即可。
之后从第二行第二列开始推导dp表;推导公式为:dp[i][j] = Max( dp[i-1][j], dp[i][ j-w[i] ] ),即在这两值中的最大值。第一个值表示不选当前第i个物品;第二个值表示第i个物品选择一个,然后用剩下容量在现在的可选范围内选出最大价值。
代码如下:
import java.util.*;
public class 完全背包问题 {
static int[] w = {2,1,3,2};//物品的重量
static int[] v = {3,2,4,2};//物品的价格
static int W = 10;//袋子最大容量
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int[][] dp = new int[4][10+1];//dp表
System.out.println(dp(dp));
}
private static int dp(int[][] dp) {
int row = dp.length;
int col = dp[0].length;
for(int i=0; i<col; i++){//初始化第一行
dp[0][i] = (i/w[0])*v[0];
}
for(int i=0; i<row; i++){//初始化第一列
dp[i][0] = 0;
}
//推导dp表
for(int i=1; i<row; i++){
for(int j=1; j<col; j++){
if(j>=w[i])//当前的最大容量能够装下第i个物品
dp[i][j] = Math.max(dp[i-1][j],v[i] + dp[i][j-w[i]]);
else
dp[i][j] = dp[i-1][j];
}
}
return dp[row-1][col-1];
}
}