01背包问题 java

01背包问题是动态规划中的经典问题

一、问题描述:有n 个物品,它们有各自的重量和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?

解决这个题有两种方法,和其它的动态规划问题一样

数组w[]为物品的重量,v[]为物品的价值

一种是递归的思想,从后向前考虑,背包决定是否放一个物品是根据两个值的大小判断(一个值是背包没有放入这个物品的价值,另一个值是背包放入这个物品,另外背包容量减少物品重量的价值),去两个值中的最大值,递归结束条件是物品放完或者是背包容量小于等于0

量化为公式就是

    public int recursiveBackpack1(int[] w, int[] v, int size) {
        if (w.length != v.length) return -1;
        int n = w.length;
        return bestValue1(w, v, n - 1, size);
    }

    private int bestValue1(int[] w, int[] v, int index, int size) {
        if (index < 0 || size <= 0) return 0;

        int res = bestValue1(w, v, index - 1, size);
        if (size >= w[index]) {
            res = max(v[index] + bestValue1(w, v, index - 1, size - w[index]), res);
        }
        return res;
    }

如果觉得递归太慢,可以将递归中重复的值放在数组里,然后调用的时候,如果要返回的位置有值,直接返回该值

    public int recursiveBackpack2(int[] w, int[] v, int size) {
        if (w.length != v.length) return -1;

        int n = w.length;
        memo = new int[n][size + 1];
        return bestValue2(w, v, n - 1, size);
    }

    private int bestValue2(int[] w, int[] v, int index, int size) {
        if (index < 0 || size <= 0) return 0;
        if (memo[index][size] != 0) {
            return memo[index][size];
        }
        int res = bestValue1(w, v, index - 1, size);
        if (size >= w[index]) {
            res = max(v[index] + bestValue1(w, v, index - 1, size - w[index]), res);
        }
        memo[index][size] = res;
        return res;
    }

接下来就是动态规划的思想,动态规划是从前往后想

求这个背包问题首先要画一个表

横轴是容量,纵轴是物品id

求解问题的过程就是维护这个表的过程,求解的值,就是最后一个空格的值

首先对于第0号物品

容量为0时,由于自身重量为1,所以放不进去,所以空格填0,容量为1以后,该物品可以放进去了,就都为6

对于第1号物品

对于(2,1)这个位置,由于背包容量是2,所以我可以放1号物品,将0号物品拿出来,或者不放1号物品,判断两种情况下的最大值,是第一种情况。

对于(3,1)这个位置,背包容量为3,可以1,0两个物品都放,或者保持(2,1),结果两个都放是最大值。

对于第2号物品

(3,2)这个位置是(0,1)+2号物品的价值和(3,1)比大小,结果是(3,1)比较大,所以还是16

(4,2)这个位置是(1,1)+2号物品的价值和(4,1)比大小,结果是(1,1)+12大,所以为18

(5,2)这个位置是(2,1)+2号物品的价值和(5,1)比大小,结果是(2,1)+12大,所以为22

所以最后背包的最大值为22

    public int backpack(int[] w, int[] v, int size) {
        if (w.length != v.length) return -1;

        int n = w.length;
        if (n == 0) return 0;
        int[][] memo1 = new int[n][size + 1];

        for (int i = 0; i <= size; i++) {
            memo1[0][i] = (i >= w[0] ? v[0] : 0);
        }
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= size; j++) {
                memo1[i][j] = memo1[i - 1][j];
                if (j >= w[i]) {
                    memo1[i][j] = max(memo1[i][j], v[i] + memo1[i - 1][j - w[i]]);
                }
            }
        }
        return memo1[n - 1][size];
    }    

参考:

bobo老师视频:https://coding.imooc.com/lesson/82.html#mid=2955

猜你喜欢

转载自blog.csdn.net/zyh568879280/article/details/88071196