(十二)动态规划--01背包

贼,夜入豪宅,可偷之物甚多,而负重能力有限,偷哪些才更加不枉此行(价值)?

抽象的话,就是:

给定一组多个()物品,每种物品都有自己的重量()和价值(),在限定的总重量/总容量()内,选择其中若干个(也即每种物品可以选0个或1个),设计选择方案使得物品的总价值最高。

 更加抽象的话:

给定正整数、给定正整数,求解0-1规划问题:

 , s.t.  ,  。(在限重情况下,价值最大,其中物品不可切割)

表达式中各个符号的具体含义:

定义子问题  为:在前  个物品中挑选总重量不超过  的物品,每种物品至多只能挑选1个,使得总价值最大;这时的最优值记作  ,其中  ,  。

考虑第  个物品,无外乎两种可能:选,或者不选。

  • 不选的话,背包的容量不变,改变为问题  ;
  • 选的话,背包的容量变小,改变为问题  。

最优方案就是比较这两种方案,哪个会更好些:

 。

(十二)动态规划--01背包_第1张图片

(十二)动态规划--01背包_第2张图片

https://blog.csdn.net/sinat_34022298/article/details/77653693    对这个转移公式进行讲解,这里简单说明

动态规划是“全局最优解包含局部最优解”,所以要求最终的要m(n,c)要求出这个数组之前的数据

假设容量C=3  体积:5  4  3

d(i,j):前i个宝石转到剩余体积为j的背包中能达到的最大价值

d(2,7) --d(3,10)

若放入3号,则d(2,10-3)+12=d(2,7)+12

若不放3号,则d(2,10)

然后考虑max即可

“填二维表”的动态规划方法

当逐步推出表中每个值的大小,那个最大价值就求出来了。推导过程中,注意一点,最好逐行而非逐列开始推导,先从编号为1的那一行,推出所有c[1][m]的值,再推编号为2的那行c[2][m]的大小。这样便于理解。

(十二)动态规划--01背包_第3张图片

思路厘清后,开始编程序,Java代码如下所示

(十二)动态规划--01背包_第4张图片

import java.util.*;

public class test {

    public static int getMaxValue(int[] weight, int[] value, int w, int n) {
        int[][] table = new int[n + 1][w + 1];
        for (int i = 1; i <= n; i++) { //物品
            for (int j = 1; j <= w; j++) {  //背包大小
                if (weight[i] > j) {        
                        //当前物品i的重量比背包容量j大,装不下,肯定就是不装
                    table[i][j] = table[i - 1][j];
                    // System.out.print(table[i][j]+ " ");
                } else { //装得下,Max{装物品i, 不装物品i}
                    table[i][j] = Math.max(table[i - 1][j], table[i - 1][j - weight[i]] + value[i]);
                    //System.out.print(table[i][j]+ " ");
                }
            }
            // System.out.println();
        }
        return table[n][w];
    }

    public static void main(String[] args) {

        int n = 5, w = 10;                    //物品个数,背包容量
        int[] value = {0, 6, 3, 5, 4, 6};     //各个物品的价值
        int[] weight = {0, 2, 2, 6, 5, 4};    //各个物品的重量
        System.out.println(getMaxValue(weight,value,w,n));

    }
}

 

你可能感兴趣的:(数据结构)