• 完全背包问题


    完全背包问题

    完全背包是背包问题的基础问题之一,和前面介绍的01背包类似,唯一的不同的是每件物品不再是只有一件,而是无限件

    01背包前面已经做了简单的总结。https://blog.csdn.net/u014532901/article/details/79835712

    完全背包问题的描述如下:

    给定nn件物品,对于第ii件物品,其价值为vivi,重量为wiwi,与此同时还存在一个体积为VV的背包,每件物品有无限件,求背包能装下的物品的最大价值PP

    对应的模型为:

    s.t.  ni=1 wixi<=V,xiNs.t.  ∑i=1n wi∗xi<=V,xi∈N

    maxP=ni=1viximaxP=∑i=1nvi∗xi

    解法

    解法同01背包十分类似,状态转移方程为:

    {fi,j=fi1,jif wi>jfi,j=max(fi1,j,fi,jwi+vi) if wi<=j{fi,j=fi−1,jif wi>jfi,j=max(fi−1,j,fi,j−wi+vi) if wi<=j
    • 01背包的状态转移方程是:fi,j=max(fi1,j,fi1,jwi+vi)fi,j=max(fi−1,j,fi−1,j−wi+vi)
    • 完全背包的状态转移方程是:fi,j=max(fi1,j,fi,jwi+vi)fi,j=max(fi−1,j,fi,j−wi+vi)

    fi,jfi,j表示前ii种物品装进容量为jj的背包里面获取的最大价值,因此对于第ii件物品来放进大小为jj的背包来讲:

    • 如果wi>jwi>j,那么该物品放不进去,则此时的收益和前i1i−1件物品放进大小为jj的背包的最大收益一样,即fi,j=fi1,jfi,j=fi−1,j
    • 若果wi<=jwi<=j, 则该物品可以放进去,但是此时是有两种选择的,即放进去或者不放进去,因此需要评估两种选择的收益大小:
      • 将第ii件物品不放进去:收益为fi1,jfi−1,j
      • 将第ii件物品放进去,但是由于第ii件物品有无限件,同01背包中不一样,我们的上一个状态不仅仅可以是:i1i−1件商品放进背包大小为jwij−wi中的最大收益值,还可以更进一步选择更新的状态:ii件物品放进大小为jwij−wi的背包中的最大收益值。此时前一个状态是:i1i−1件物品放进大小为jwij−wi的背包中。因此将第ii件物品放入背包的收益是fi,jwi+vifi,j−wi+vi
      • 最后两个方案中最大的收益便是当前的收益

    代码和01背包代码类似:

    
        public static int knapsackProblemCompletion(int[] value, int[] weight, int bagV) {
            int n = value.length;
            int[][] dp = new int[value.length][bagV + 1];
            for (int i = 1; i < n; i++) {
                for (int j = 1; j <= bagV; j++) {//注意这里j是从1开始的
                    if (weight[i] > j) {
                        dp[i][j] = dp[i-1][j];
                    }
                    else {
                        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]);
                    }
                }
            }
    
            return dp[n - 1][bagV];
        }
    
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            int[] value = new int[] { 0, 1, 4, 3,6};// 物品的价值
            int[] weight = new int[] { 0, 5, 2, 4, 3};// 物品的重量
            int bagV = 15;// 背包的大小
            System.out.println(knapsackProblemCompletion(value, weight, bagV));
        }
    

    算法的时间复杂度为: O(NV)O(NV),空间复杂度为:O(NV)O(NV)

    二维状态数组可以用如下的二维表格表示:

    这里写图片描述

    空间优化

    由前面的状态转移方程我们可以知道,fi,jfi,j的状态只和前一轮的状态fi1,jfi−1,j和本轮的稍早的某个状态fi,jwifi,j−wi有关,因此可以像01背包问题一样,将二维数组优化为一维滚动数组,优化后空间复杂度降为O(V)O(V)

    
    public static int knapsackProblemCompletionOptimization(int[] value, int[] weight, int bagV) {
            int n = value.length;
            int[] dp = new int[bagV+1];
            for (int i = 1; i < n; i++) {
                for (int j = weight[i]; j <= bagV; j++) {
                    dp[j] = Math.max(dp[j], dp[j-weight[i]] + value[i]);
                }
            }
            return dp[bagV];
        }
    

    特别注意这里的内部循环的循环顺序:

    for (int j = weight[i]; j <= bagV; j++) 

    状态回溯

    有时候我们不仅仅需要找到能到到最优收益值,还需要找到具体的装包方案,我们可以根据状态数组从后往前倒推得出装包方案。

    
        public static int[] tracbackCompletion(int[][] dp, int[] weight, int bagV) {
            int[] res = new int[weight.length];
            int j = bagV;
            for (int i = weight.length - 1; i >= 1; i--) {
                //从后往前追踪,dp[i][j]要么来自dp[i-1][j],要么来自dp[i][j-weight[i]]
                while (dp[i][j] != -1 && dp[i][j] != dp[i-1][j]) {
                    res[i] += 1;
                    j -= weight[i];
                }
            }
            res[0] = dp[0][j] > 0 ? res[0] + 1 : res[0];
            return res;
        }
    

    这里写图片描述

    总结

    完全背包是背包问题的基础问题问题之一,和01背包非常类似但是也有些许区别。
    完全背包和01背包的区别:完全背包的物品是无限的,而01背包的物品只有一件。

    两者的状态转移方程为:

    • 01背包的状态转移方程是:fi,j=max(fi1,j,fi1,jwi+vi)fi,j=max(fi−1,j,fi−1,j−wi+vi)
    • 完全背包的状态转移方程是:fi,j=max(fi1,j,fi,jwi+vi)fi,j=max(fi−1,j,fi,j−wi+vi)
  • 相关阅读:
    SQL Server 自定义函数(Function)——参数默认值
    SQL Server返回插入数据的ID和受影响的行数
    SQL Server去重和判断是否为数字——OBJECT_ID的使用
    SQL Server插入数据和删除数据
    SQL Server语句创建数据库和表——并设置主外键关系
    SQL Server 数据分页查询
    C# ref、out、params与值类型参数修饰符
    C#字符串的方法
    C#数组的声明
    tcpdump的使用
  • 原文地址:https://www.cnblogs.com/Spground/p/9567880.html
Copyright © 2020-2023  润新知