动态规划之背包问题详解

动态规划之背包问题详解

说明

  1. 动态规划也是一种将复杂问题拆解为许多子问题的一种算法,与分治算法类似,只不过动态规划拆解后的子问题是互相有关联的,而分治拆解后的子问题彼此没有关联
  2. 背包问题是指有一堆物品,每个物品都有自己的价格,现有一个背包,有一定的存储容量,现要求背包能存储物品的最大价值为多少,即背包中存储那些物品使得这些物品占有的价值最大,,物品不能重复
  3. 可以使用动态规划,动态规划可以使用填表法来实现,具体用程序完成,即使用二维数组,二维数组的行表示背包的容量,从0开始到最大,二维数组的列为物品,从零开始递增,一直到最后一件物品
  4. 先将二维数组的第一行第一列置为0,表示物品数为0,背包容量为0时背包的最大价值为0
  5. 用两个一维数组,一个记录物品,一个记录价格,两个数组应该有一一对应的关系
  6. 则开始填充二维数组,即表,开始遍历二维数组填充
  7. 如果二维数组当前位置:要放入的物品质量大于背包容量,则不能放入当前物品
  8. 如果要放入的物品质量小于当前位置的背包容量,则可以放入当前物品,而且还要有一定的剩余空间,再判断剩余的空间还能不能放入其他的物品,如果还能放入,则加入,如果不能就只能空着
  9. 上述思路执行完毕后,遍历二维数组则会看到背包物品放入的结果
  10. 源码见下

源码及分析

public static void main(String[] args) {
        //物品质量
        int[] w = {1, 4, 3};
        //物品价值
        int[] value = {1500, 3000, 2000};
        //背包容量
        int m = 4;
        //物品个数
        int n = w.length;
        //创建二维数组类似一张表,使用填表法完成动态规划
        int[][] v = new int[n + 1][m + 1];
        int[][] path = new int[n + 1][m + 1];
        //将二维数组的第一行第一列置为0
        for (int i = 0; i < v.length; i++) {
            v[i][0] = 0;
        }
        for (int i = 0; i < v[0].length; i++) {
            v[0][i] = 0;
        }
        //使用动态规划向背包中添加物品
        for (int i = 1; i < v.length; i++) {
            for (int j = 1; j < v[0].length; j++) {
                //如果背包的的容量小于物品的质量,则无法存放
                if (j < w[i - 1]) {
                    v[i][j] = v[i - 1][j];
                } else {
                    //如果背包的容量大于当前物品的质量,将当前物品放入背包后考虑剩余空间是否还可以存储一个物品
                    //v[i][j] = Math.max(v[i - 1][j], value[i - 1] + v[i - 1][j - w[i - 1]]);
                    if (value[i - 1] + v[i - 1][j - w[i - 1]] > v[i - 1][j]) {
                        v[i][j] = value[i - 1] + v[i - 1][j - w[i - 1]];
                        //如果还能存储一个物品,将当前位置置为1
                        path[i][j] = 1;
                    } else {
                        //否则就空着
                        v[i][j] = v[i - 1][j];
                    }
                }
            }
        }

        //查看背包的情况
        for (int i = 0; i < v.length; i++) {
            for (int j = 0; j < v[i].length; j++) {
                System.out.print(v[i][j] + "\t");
            }
            System.out.println();
        }
        //输出将那些物品放入背包
        //行和列的最大值
        int i = path.length - 1;
        int j = path[0].length - 1;
        //循环结束的条件
        while (i > 0 && j > 0) {
            if (path[i][j] == 1) {
                System.out.printf("第%d个商品放入背包\n", i);
                //减去当前物品的重量
                j -= w[i - 1];
            }
            i--;
        }
    }
posted @ 2021-06-14 20:26  mx_info  阅读(16)  评论(0编辑  收藏  举报