zl程序教程

您现在的位置是:首页 >  其他

当前栏目

动态规划处理01背包问题

2023-03-07 09:40:53 时间

对于物品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