01背包 动态规划(三)
01背包问题详解,暴力递归改动态规划
测试数据:
int n=5;//物品个数
int m=20;//背包容量
int[] weight=new int[]{0,2,3,4,5,9};//物品重量
int[] value=new int[]{0,3,4,5,8,10};//物品价值
1.递归版本:
private static int knapsack(int n,int m,int[] w,int[] v) {
if(n==0||m==0){
return 0;
}else if((m>w[n])&&((knapsack(n-1, m-w[n], w, v)+v[n])>knapsack(n-1, m, w, v))){
return knapsack(n-1, m-w[n], w, v)+v[n];
}else{
return knapsack(n-1, m, w, v);
}
}
2.分析可变参数,哪几个可变参数的值能代表返回状态,几个可变参数,就构造几维表。
本题中,背包所装得物品的最大价值只与背包容量和物品个数有关,所以dp表为二维:
3.根据base case填表:
if(n==0||m==0){
return 0;
}
n\m | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | ||||||||||||||||||||
2 | 0 | ||||||||||||||||||||
3 | 0 | ||||||||||||||||||||
4 | 0 | ||||||||||||||||||||
5 | 0 |
if((m>w[n])&&((knapsack(n-1, m-w[n], w, v)+v[n])>knapsack(n-1, m, w, v))){
return knapsack(n-1, m-w[n], w, v)+v[n];
}else{
return knapsack(n-1, m, w, v);
}
如果一个位置的列(即背包容量)>它的w[n](即物品质量),要知道这个位置的值,就得知道它(上一行,本列+w[n])+v[n] 元素的值和(上一行,本列) 元素的值,取其二者中最大值;
如果一个位置的列(即背包容量)<= 它的w[n](即物品质量),要知道这个位置的值,就得知道它(上一行,本列)元素的值。
补全dp表(略,见下图):
n\m | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 00 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | ||||||||||||||||||||
2 | 0 | ||||||||||||||||||||
3 | 0 | ||||||||||||||||||||
4 | 0 | ||||||||||||||||||||
5 | 0 |
动态规划的代码为:
// dp
private static int dpknapsack(int n, int m, int[] w, int[] v) {
int[][] dp = new int[n + 1][m + 1];
// for (int i = 0; i < n + 1; i++) {
// dp[i][0] = 0;
// }
// for (int j = 0; j < m + 1; j++) {
// dp[0][j] = 0;
// }
for (int i = 1; i < n + 1; i++) {
for (int j = 1; j < m + 1; j++) {
if (j > w[i]) {
int value1 = dp[i - 1][j - w[i]] + v[i];
int value2 = dp[i - 1][j];
dp[i][j] = value1 > value2 ? value1 : value2;
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
for (int x = 0; x < n + 1; x++) {
for (int y = 0; y < m + 1; y++) {
System.out.print(dp[x][y] + "\t");
}
System.out.println("");
}
return dp[n][m];
}