赞
踩
引言:
01背包问题是比较基本的一种背包类型,起特征是背包内的物品只能取一次。
常规解法
对于常规解法就是构建一个二维的dp数组进行求解,主要问题在于选与不选
这里贴上完整的代码
private static int knapsack(int w, int n, int[] wt, int[] val) { // 二维数组:状态定义:dp[i][j]表示从0-i个物品中选择不超过j重量的物品的最大价值 int[][] dp = new int[n + 1][w + 1]; int[][] g = new int[n + 1][w + 1]; //base case // 初始化:第一列都是0,第一行表示只选取0号物品最大价值 for (int j = w; j >= wt[0]; j--) { dp[0][j] = dp[0][j - wt[0]] + val[0]; // System.out.println(dp[0][j]); g[0][j] = 1; } for (int i = 1; i < wt.length; i++) { for (int j = 0; j <= w; j++) { if (j < wt[i]) { //当前背包装不下,只能选择不装入背包 dp[i][j] = dp[i - 1][j]; g[i][j] = 0; } else { //装入或者不装择优选择 // dp[i][j]=Math.max(dp[i-1][j-wt[i]]+val[i],dp[i-1][j]); if (dp[i - 1][j - wt[i]] + val[i] >= dp[i - 1][j]) { dp[i][j] = dp[i - 1][j - wt[i]] + val[i]; g[i][j] = 1; } else { dp[i][j] = dp[i - 1][j]; g[i][j] = 0; } } } } int i = wt.length, V = w; ListUtil.arrayTowNums(g); System.out.println(); while (i >= 0) { if (g[i][V] == 0) { i--; } else { System.out.print(i + " "); V -= wt[i]; i--; } } return dp[n - 1][w]; }
特别要注意上面的g标记二维数组
其作用就是标记当某个物品被选择时,起就设为1,之后将添加的物品一个个取出
//装入或者不装择优选择
// dp[i][j]=Math.max(dp[i-1][j-wt[i]]+val[i],dp[i-1][j]);
if (dp[i - 1][j - wt[i]] + val[i] >= dp[i - 1][j]) {
dp[i][j] = dp[i - 1][j - wt[i]] + val[i];
g[i][j] = 1;
} else {
dp[i][j] = dp[i - 1][j];
g[i][j] = 0;
}
倒过去取出,判断标记数组g[i][j]的值
int i = wt.length, V = w;
ListUtil.arrayTowNums(g);
System.out.println();
while (i >= 0) {
if (g[i][V] == 0) {
i--;
} else {
System.out.print(i + " ");
V -= wt[i];
i--;
}
}
最后再来个压缩过空间的完整版本
private static int knapsack2(int w, int n, int[] wt, int[] val) { int[] dp = new int[w + 1]; int[][] g = new int[n + 1][w + 1]; for (int i = 0; i <n; i++) { for (int j = w; j >= wt[i]; j--) { g[i][j]=0; if (dp[j]<dp[j - wt[i]] + val[i]){ dp[j]=dp[j - wt[i]] + val[i]; g[i][j]=1; } } } int i = wt.length, V = w; ListUtil.arrayTowNums(g); System.out.println(); while (i >= 0) { if (g[i][V] == 0) { i--; } else { System.out.print(i + " "); V -= wt[i]; i--; } } return dp[w]; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。