// 模型1:从左向右尝试模型/** * 背包问题 */public class Code01_Knapsack { // 所有的货,重量和价值,都在w和v数组里 // 为了方便,其中没有负数 // bag背包容量,不能超过这个载重 // 返回:不超重的情况下,能够得到的最大价值 /** * * @param w 货物数组 * @param v 重量数组 * @param bag 背包最大载重 * @return 不超重的情况下能够得到的最大价值 */ public static int maxValue(int[] w, int[] v, int bag) { // 特殊边界的情况 if (w == null || v == null || w.length != v.length || w.length == 0) { return 0; } // 尝试函数!从0号开始向右选择 return process(w, v, 0, bag); } // index 0~N // rest 负~bag /** * 方法1:暴力递归 * @param w 重量 * @param v 价值 * @param index 当前来到index位置 * @param rest 剩余背包容量 * @return */ // 从左向右尝试,当前来到了index位置。不考虑index之前的信息 public static int process(int[] w, int[] v, int index, int rest) { // 无效解设置,上游在使用时需要进行判断。 if (rest < 0) { // 背包为0时有可能装的,如规定,重为0 价值100, return -1; } // 越界位置,没有货了 if (index == w.length) { return 0; } // 有货,index位置的货物,bag有空间 // 可能性1:不要当前的货,背包剩余容量变,直接考虑下一个位置 int p1 = process(w, v, index + 1, rest); // 可能性2:要当前的货 int p2 = 0; int next = process(w, v, index + 1, rest - w[index]); // 背包不越界的情况下。 if (next != -1) { p2 = v[index] + next; } return Math.max(p1, p2); } /** * 方式2:动态规划 * * 根据暴力递归可以发现,动态变化的参数只有 index和rest * index 的范围为 0-N 在递归中N为 basecase * rest 的范围为 某个负数 - bag 0 - bag * */ public static int dp(int[] w, int[] v, int bag) { if (w == null || v == null || w.length != v.length || w.length == 0) { return 0; } int N = w.length; int[][] dp = new int[N + 1][bag + 1]; for (int index = N - 1; index >= 0; index--) { // 从边界开始 for (int rest = 0; rest <= bag; rest++) { int p1 = dp[index + 1][rest]; int p2 = 0; int next = rest - w[index] < 0 ? -1 : dp[index + 1][rest - w[index]]; if (next != -1) { p2 = v[index] + next; } dp[index][rest] = Math.max(p1, p2); } } return dp[0][bag]; } public static void main(String[] args) { int[] weights = { 3, 2, 4, 7, 3, 1, 7 }; int[] values = { 5, 6, 3, 19, 12, 4, 2 }; int bag = 15; System.out.println(maxValue(weights, values, bag)); System.out.println(dp(weights, values, bag)); }}