当前位置: 移动技术网 > IT编程>开发语言>Java > 辅助理解01背包问题和完全背包问题的优化思想

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

2020年07月31日  | 移动技术网IT编程  | 我要评论
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
    第0层

  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时的最大价值,即实现了物品的重复使用
    此时,内循环完成,得到了当前能够获得的最大价值。
    第1层

  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,继续遍历,最后得到如下:
    第2层

  4. 第3层,得到的结果为
    第4层
    5.第4层,得到的结果为
    第5层

3、 01背包

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

  1. 第0层,同样,直接初始化为0,为第1层做铺垫
    第0层
  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的值来体现的,完全背包也是一样,因为前面的更新了后面,实现了物品价值的累加)。
    在这里插入图片描述
  3. 第2层,结果如下
    在这里插入图片描述
  4. 第3层,结果如下
    在这里插入图片描述
  5. 第4层,结果如下
    在这里插入图片描述

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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网