欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

辅助理解01背包问题和完全背包问题的优化思想

程序员文章站 2022-09-16 21:09:25
1、先上代码(Java)import java.util.Arrays;public class CompleteBackpack { private int[] weight, value; //重量,价值 private static int cap[];//cap[i]表示可用重量为i时的最大价值 private int C;//最大容量 //01背包 public int knapsack01() { int length = weig...

1、先上代码(Java)

import java.util.Arrays;

public class CompleteBackpack {
    private int[] weight, value; //重量,价值
    private static int cap[];//cap[i]表示可用重量为i时的最大价值
    private int C;//最大容量

    //01背包
    public int knapsack01() {
        int length = weight.length;
        if (length == 0) return 0;
        for (int i = 1; i <= length; i++) {
            for (int j = C; j >=weight[i-1]; j--) { //自顶向下
                cap[j]=Math.max(cap[j], cap[j-weight[i-1]]+value[i-1]);
            }
        }
        return cap[C];
    }

    //完全背包
    public int completeknapsack() {
        int length = weight.length;
        if (length == 0) return 0;
        for (int i = 1; i <= length; i++) {
            for (int j = weight[i-1]; j <= C; j++) { //自底向上
                cap[j] = Math.max(cap[j], cap[j - weight[i-1]]+ value[i-1]);
            }
        }

        return cap[C];
    }

    public void init(int[]  value, int[]  weight,int c) {
        this.weight=weight;
        this.value = value;
        this.C = c;
        cap = new int[c+1];
        Arrays.fill(cap,0);
        
    }

    public static void main(String[] args) {
        int[]  value= {8,5,4,3};
        int[]  weight= {5,4,3,2};
        int c = 10;
        CompleteBackpack knapsack = new CompleteBackpack();
        knapsack.init(value, weight, c);
        System.out.println(knapsack.knapsack01());
        System.out.println(knapsack.completeknapsack());
    }

}

2、完全背包

先分析完全背包是我认为优化后的完全背包比01背包容易理解

完全背包和01背包的这种优化思想是从建表的解法上改进了:表格中下一行的值只跟上一行有关,需要了解演变过程的同学,可以查看这篇文章,下面结合图来分析该优化的思想
优化的解法中,使用一维数组( private static int cap[ ])来做存储,其表示的含义是:cap[i]表示可用重量为i时的最大价值,理解这点很重要
下面结合上面代码来介绍

  1. 第0层,虚拟的,为第1层做铺垫,全部都初试为0
    辅助理解01背包问题和完全背包问题的优化思想

  2. 第1层,即i=1时,对于第二重for循环,j的起点为第1件物品的重量,这里很明显,如果可用重量j低于这件物品的重量,肯定是无法放入背包中。然后在可用重量j从5到9的过程中,最大价值都是8,以j=5时举例,在上一层,即第0层中,可用重量为j时,最大价值为0,即如果不将第1件物品放入背包,那么此时最大价值为0,记为价值A,而如果将第1件物品放入背包中,那么此时最大价值为cap[5 - weight[0]]+ value[0],即不放入第1件物品时的最大价值+第1件物品的价值,记为价值B,比较A和B,取最大值作为此时可用重量的最大价值。在这里可以看到,当可用重量j为5时,不放入第1件物品的最大价值为cap[0],随着可用重量j的不断增大,直到9,最大价值取得的方式都是0+8,而当j到10,背包中可以容纳两个 第1件物品,,此时最大价值变为
    cap[10 - weight[0]]+ value[0]=cap[5]+8=8+8=16
    这里用到了可用重量为5时的最大价值,即实现了物品的重复使用
    此时,内循环完成,得到了当前能够获得的最大价值。
    辅助理解01背包问题和完全背包问题的优化思想

  3. 第2层,下面,第2件物品入场了。
    依据上面的思路,第2件物品的重量为4,那么可用重量j从4开始,可用得到cap[4]=5,然后继续往下遍历,当可用重量j变为8时,cap[8-weight[1]]+value[1]=5+8=13,与上一层可用重量为8时的最大价值cap[8]=8相比较,更新可用重量为8时的最大价值为13,继续遍历,最后得到如下:
    辅助理解01背包问题和完全背包问题的优化思想

  4. 第3层,得到的结果为
    辅助理解01背包问题和完全背包问题的优化思想
    5.第4层,得到的结果为
    辅助理解01背包问题和完全背包问题的优化思想

3、 01背包

分析完完全背包,再来看01背包问题就简单了,同样,优化的解法中,使用一维数组( private static int cap[ ])来做存储,其表示的含义是:cap[i]表示可用重量为i时的最大价值
01背包与完全背包最大的不同,就是物品不能重复选择,一件物品只能选择一次,所以在更新cap[i]时,就不能像完全背包那样,那么要如何实现在新一轮更新中,即要使用上一轮的结果,又要使得这轮前面更新的结果不会对后面的更新产生影响(即同一个物品重复使用问题)?
答案就是跟完全背包反着来,因为完全的内循环是自底向上,那么反过来就是自顶向下。

  1. 第0层,同样,直接初始化为0,为第1层做铺垫
    辅助理解01背包问题和完全背包问题的优化思想
  2. 第1层,可用重量j从10开始,逐步减小,直到等于第1件物品的重量(再减小的话,就放不进背包了),以可用重量j=10来举例,上层cap[10]=0,即不放第1件物品的情况,如果要放入的话,那么上一层的最大价值应该是cap[10-5],放入后,总的最大价值为cap[10-5]+value[0]=0+8=8,比较放跟不放的情况,取最大值,得cap[10]=8。接下来是可用重量j=9,上层cap[9]=0,这是不放第1件物品的情况,如果放入就变成了cap[9-5]+value[0]=8,可得cap[9]=8。同理,可以得到下图的结果,从这个过程中,我们可以发现,在这一轮的更新过程中(或者说一次内循环过程),前面的更新不会影响后面的更新(这里的前面、后面不是指数组cap的前后,而是更新过程的前后,两者是相反的,cap中靠前的元素,是最后更新的),这样一件物品只会被放入一次(是否放入是从cap的值来体现的,完全背包也是一样,因为前面的更新了后面,实现了物品价值的累加)。
    辅助理解01背包问题和完全背包问题的优化思想
  3. 第2层,结果如下
    辅助理解01背包问题和完全背包问题的优化思想
  4. 第3层,结果如下
    辅助理解01背包问题和完全背包问题的优化思想
  5. 第4层,结果如下
    辅助理解01背包问题和完全背包问题的优化思想

本文地址:https://blog.csdn.net/weixin_44219085/article/details/107687922

相关标签: 算法