问题描述:给定n个物品,每个物品有一个重量w和价值v,你有一个能装m重量的背包,问怎么装使得所装价值最大,每个物品只有一个。
如:n = 3, m = 5, wi = {2,3,4}; vi = {3,5,7};
结果返回最大价值为:8
首先来填一个表格-->
第一,如果背包容量比该物品重量小,要不起,此时的价值等于[i - 1][ j ]格中的价值。
第二,如果背包容量可以装下该物品,要的起,但是会存在装了之后不一定价值超过没装之前。所以要在要和不要之间取一个最大值,要的话就得从当前背包容量减去物品重量,再从剩下容量的那一列去找,再加上要拿的物品价值。
即dp[i][j] = max( dp[i-1][j], dp[i-1][j - w[i] ] + v[i] );
一定要记得初始化第一行,如果j>=w[i],dp[0][j] = v[0];否则的话就是要不起dp[0][j] = 0;
下面直接上代码:
public class _01_knapsack {
private static int n = 3;//物品数量
private static int m = 5;//背包容量
private static int[] w = {2,3,4};
private static int[] v = {3,5,7};
public static void main(String[] args) {
_01_knapsack tem = new _01_knapsack();
int res = tem.dp();
System.out.println(res);
}
public int dp(){
int[][] dp = new int[n][m+1];
//初始化第一行
for(int j = 0;j <= m;j++){
if(j >= w[0]){
dp[0][j] = v[0];//要的起,背包价值更新,物品只有一个,背包容量再大,价值也不变
}else{
dp[0][j] = 0;//要不起,价值为0
}
}
for(int i = 1;i < n;i++){
for(int j = 0;j <= m;j++){
if(j>=w[i]){
int a = dp[i-1][j];
int b = dp[i-1][j - w[i]] + v[i];
dp[i][j] = Math.max(a, b);
}else{
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[n-1][m];//表格右下角为最大价值
}
}