动态规划解决0-1背包问题升级版–计算价值最高

需求:对于一组不同重量、不同价值、不可分割的物品,我们需要选择一些装入背包,计算满足背包重量的前提下,装入背包的物品的最大价值是多少呢?
之所以叫0-1背包问题,就是因为物品不可分割。

相比前面的0-1背包问题,这里的升级版问题引入了物品价值,考虑的维度多了一个。

我们先回顾一下之前讲过的回溯算法的逻辑:
动态规划的实现逻辑是根据前面计算的状态结果来决定后续计算,但是不考虑之前的结果是如何计算的,既然要根据前面的状态,那么就要把前面计算的状态结果保存下来,这就需要申请额外的空间。
动态规划也有公式,就跟递归有递归公式一样,写动态规划就是写动态规划公式。
简单来说动态规划的重点:
1、基于前面的计算结果来进行后续计算。
2、编写动态规划公式。

我们来看代码,理解一下上面的理论。

public class BeiBao_DongTaiGuiHua2 {

    // 物品重量
    private static final int[] weight = {2, 2, 4, 6, 3};

    // 物品的价值
    private static int[] value = {5, 2, 8, 12, 6};

    // 物品个数
    private static final int n = 5;

    // 背包承受的最大重量
    private static final int w = 9;

    public static void main(String[] args) {
        BeiBao_DongTaiGuiHua2.getMaxWeight();
        /*System.out.println("-------------------------------------");
        BeiBao_DongTaiGuiHua2.getMaxWeight2();
        System.out.println("-------------------------------------");
        BeiBao_DongTaiGuiHua2.getMaxWeight3();*/
    }

    public static void getMaxWeight() {
        //定义标记数组
        int[][] wFlag = new int[n][w + 1];

        for (int x = 0; x < wFlag.length; x++) {
            for (int y = 0; y < wFlag[x].length; y++) {
                wFlag[x][y] = -1;
            }
        }

        //初始化第一个物品的标记结果
        wFlag[0][0] = 0;
        if (weight[0] < w) {
            wFlag[0][weight[0]] = value[0];
        }

        //动态规划计算背包结果
        for (int x = 1; x < n; x++) {
            //第x个商品不放进背包
            for (int y = 0; y <= w; y++) {
                if (wFlag[x - 1][y] >= 0) {
                    wFlag[x][y] = wFlag[x - 1][y];
                }
            }

            //第x个商品放进背包
            for (int y = 0; y <= w - weight[x]; y++) {
                System.out.println("当前第:" + (x + 1) + "个商品,当前计算位置:" + y);
                if (wFlag[x - 1][y] >= 0) {
                    if (wFlag[x - 1][y] + value[x] > wFlag[x][y + weight[x]]) {
                        wFlag[x][y + weight[x]] = wFlag[x - 1][y] + value[x];
                    }
                }
            }

            System.out.println("------------------------------------------");
        }

        //打印结果
        int max = Integer.MIN_VALUE;
        for (int x = w; x >= 0; x--) {
            if (max < wFlag[n - 1][x]) {
                max = wFlag[n - 1][x];
            }
        }
        System.out.println("背包中最大重量为:" + max);

    }
}

/* 输出
当前第:2个商品,当前计算位置:0
当前第:2个商品,当前计算位置:1
当前第:2个商品,当前计算位置:2
当前第:2个商品,当前计算位置:3
当前第:2个商品,当前计算位置:4
当前第:2个商品,当前计算位置:5
当前第:2个商品,当前计算位置:6
当前第:2个商品,当前计算位置:7
------------------------------------------
当前第:3个商品,当前计算位置:0
当前第:3个商品,当前计算位置:1
当前第:3个商品,当前计算位置:2
当前第:3个商品,当前计算位置:3
当前第:3个商品,当前计算位置:4
当前第:3个商品,当前计算位置:5
------------------------------------------
当前第:4个商品,当前计算位置:0
当前第:4个商品,当前计算位置:1
当前第:4个商品,当前计算位置:2
当前第:4个商品,当前计算位置:3
------------------------------------------
当前第:5个商品,当前计算位置:0
当前第:5个商品,当前计算位置:1
当前第:5个商品,当前计算位置:2
当前第:5个商品,当前计算位置:3
当前第:5个商品,当前计算位置:4
当前第:5个商品,当前计算位置:5
当前第:5个商品,当前计算位置:6
------------------------------------------
背包中最大重量为:19
 */

标记状态的数据wFlag的状态推演:

简单背包问题中我们还将wFlag标记数组从二维优化到了一维,但是在背包升级问题中,就不能优化了,因为这里我们要计算的是最大价值,wFlag的类型也从boolean[][]变为了int[][]。
wFlag[][]中存的是对应的物品价值。