zoukankan      html  css  js  c++  java
  • 动态规划处理01背包问题

    对于物品X, 重量, 价值和背包总容量为以下数值的情况下, 求在背包容量限制下得到最大价值的物品组合方式

    5个物品,(重量w,价值v)分别为:(5,12),(4,3),(7,10),(2,3),(6,6)

    1. 假设最优答案

    我们假设最优答案为00011。这样根据动态规划要求,考虑最优子问题。一般考虑子问题都是减少问题包含元素数量,同时保持子问题与原问题属于同种问题,只是考虑数量减少了。比如我们减少第五个物品, 那么子问题就是

    4个物品,(重量w,价值v)分别为:(5,12),(4,3),(7,10),(2,3)

    2. 找到原问题与子问题之间联系

    如果00011为原问题最优解, 那么0001就是子问题最优解. 如果0001不是子问题最优解, 假设0101为子问题最优解, 那原问题最优解就是01011, 与我们假设相悖. 那么从子问题到原问题要经过什么样考虑? 假定现在已经找到子问题最优解, 到原问题解我们只需考虑第五个物品是取还是不取. 如果取, 那么取以后背包空余量减少, 背包价值增大, 如果弃, 那么子问题的条件有变化(空间增大了), 可能有更优的子问题最优解, 背包价值也会变, 所以要比较这两者哪个价值更大:
    1) 如果最优解包含了物品n,即物(n)=1,那么其余物1,物2,…,物(n-1) 一定构成子问题1,2,…,n-1在背包容量W-w(n)时的最优解
    2) 如果最优解不包含物品n,即物(n)=0,那么其余物1,物2,…,物(n-1)一定构成子问题1,2,…,n-1在背包容量W时的最优解。

    3. 公式的建立
    根据上一步, 就能知道, 在加上第五个物品后, 只需要判断两种情况下的价值, 就能知道包含第五个物品时的最优解, 即
    1) 物1~物(n-1)在背包容量W-w(n)时的最大价值加上第五个物品的价值
    2) 在背包容量为W时, 物1~物(n-1)的最大价值
    所以有

    cell[i][j] = max( cell[i-1][j-w[i]] + v[i],  cell[i-1][j])
    {i,j|0< i <=n,0<= j <=total}

    3. 代码实现, 使用Java语言

    public static void main(String[] args) {
        int[] w = {2, 2, 6, 5, 4, 3, 7}; //weight
        int[] v = {6, 3, 5, 4, 6, 6, 9}; //value
        int c = 10;            //capcity
    
        int[] x = new int[w.length];  // record
    
        int[][] m = new int[w.length][c+1];
    
        for (int i = 0; i < w.length; i++) { // for each w[i]
            for (int j = 0; j <= c; j++) { // for each capacity
                if (j < w[i]) {
                    int tmp = (i - 1) < 0 ? 0 : m[i - 1][j];
                    m[i][j] = tmp;
                    continue;
                }
                int v1 = (i - 1) < 0 ? v[i] : m[i - 1][j - w[i]] + v[i];
                int v2 = (i - 1) < 0 ? 0 : m[i - 1][j];
                if (v1 > v2) {
                    m[i][j] = v1;
                } else {
                    m[i][j] = v2;
                }
            }
        }
        for (int i = m.length - 1; i >= 0; i--) {
            for (int j = 0; j < m[i].length; j++) {
                System.out.print(String.format("%2d ",m[i][j]));
            }
            System.out.println();
        }
    
        int cap = c;
        for (int i = w.length - 1; i >= 0; i--) {
            if (i == 0) {
                if (m[i][cap] > 0) {
                    x[i] = 1;
                }
            } else {
                if (m[i][cap] > m[i - 1][cap]) {
                    x[i] = 1;
                    cap = cap - w[i];
                }
            }
        }
        for (int i = 0; i < x.length; i++) {
            if (x[i] != 0) {
                System.out.println(i + ":" + w[i] + ":" + v[i]);
            }
        }
    }
    

     运行的结果

     0  0  6  6  9 12 12 15 15 18 18 
     0  0  6  6  9 12 12 15 15 18 18 
     0  0  6  6  9  9 12 12 15 15 15 
     0  0  6  6  9  9  9 10 11 13 14 
     0  0  6  6  9  9  9  9 11 11 14 
     0  0  6  6  9  9  9  9  9  9  9 
     0  0  6  6  6  6  6  6  6  6  6 
    0:2:6 4:4:6 5:3:6
  • 相关阅读:
    洛谷 P1068 分数线划定
    LeetCode 7. Reverse Integer
    LeetCode 504. Base 7
    洛谷 P1598 垂直柱状图
    用户场景
    个人博客03
    个人博客02
    个人博客01
    《构建之法》阅读笔记03
    学习进度条(第四周)
  • 原文地址:https://www.cnblogs.com/milton/p/9263660.html
Copyright © 2011-2022 走看看