ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

动态规划问题(十)0-1 背包问题

2021-08-18 13:34:53  阅读:156  来源: 互联网

标签:背包 capacity weight int 问题 values 物品 动态


动态规划问题(十)0-1 背包问题

问题描述

​ 在一堆物品中,由相应的价值和重量,现在你有一个有容量限制的背包,每个物品你只能选择拿或者不拿。现在要求计算能够得到的最大物品的总价值。

​ 例如,对于一堆物品,它的价值为 {60, 100, 120},重量为 {10, 20, 30},你现在的背包容量为 50,因此你最大可以拿到的物品价值为 220(取第二个和第三个物品)

解决思路

​ 对于每一个物品,它最终的状态都只能要么在所选物品集合中,要么不在。因此,可以通过递归简单地枚举出所有的组合集合,从而找到价值最大的最优解。

  • 递归
    • 定义最优子集为最终会放入背包的物品集合
    • 对于每一个物品,它最终要么在最优子集中,要么不在;对于在最优子集的物品,加上它的价值,同时背包容量减去它的重量,在此基础上进行递归操作。最终得到最优子集
    • 对于重量大于背包当前容量的物品,只能选择放弃
  • 动态规划
    • 与上文递归的相对应,由于在穷举时会重复计算之前已经计算过的问题,因此可以使用动态规划来解决这一类的重复子问题

实现

  • 递归

    public class Solution {
        /**
         * 根据当前的物品信息和背包的容量信息得到能够得到的最大收益
         * @param values : 当前可选物品的价值信息列表
         * @param weight : 当前可选物品的重量信息列表
         * @param capacity :当前背包的可用容量
         * @param index : 当前待选择的物品的位置索引,类似游标
         * @return :当前条件下能够得到的最大收益
         */
        public static int knapSack(int[] values, int[] weight, int capacity, int index) {
            // 边界条件,对于背包容量为 0 或者当前无可选物品时,达到终止条件
            if (0 == capacity || 0 > index)
                return 0;
    
            // 如果当前选取的物品的重量大于背包当前的可用容量,那么就不能添加该物品了
            if (weight[index] > capacity)
                return knapSack(values, weight, capacity, index - 1);
    
            return Math.max(
                    // 假设当前选取的物品是在最优子结构中的,那么把它放入背包然后与不放入背包的情况后的结果进行比较
                    values[index]
                            + knapSack(values, weight, capacity - weight[index], index - 1),
                    knapSack(values, weight, capacity, index - 1) // 当前的物品不放入背包
            );
        }
    }
    
  • 动态规划

    public class Solution {
         public static int bagProblem(int[] values, int[] weight, int capacity) {
            int len = values.length;
            // 当前的 dp[i][j] 表示在过滤了 i 件物品后,在 j 容量的情况下能够得到的最大收益
            int[][] dp = new int[len + 1][capacity + 1];
    
            // 由于 dp 的意义,因此 i 的位置需要从 1 开始
            for (int i = 1; i <= len; ++i) {
                for (int j = 1; j <= capacity; ++j) {
                    // 如果当前的物品重量大于背包的可用容量,那么直接跳过这个物品
                    if (weight[i - 1] > j)
                        dp[i][j] = dp[i - 1][j]; // i - 1 代表当前的物品不放入背包,因为 i 在这代表的是第 i 个物品的选取情况
                    else dp[i][j] = Math.max(
                            dp[i - 1][j], // 当前的物品不放入背包的情况
                            values[i - 1] + dp[i - 1][j - weight[i - 1]] // 当前物品放入背包的情况,values 内的 i - 1 是索引,不要弄混淆了
                    );
                }
            }
    
            return dp[len][capacity];
        }
    }
    
  • 压缩空间

    可以压缩上文动态规划中的存储数组,用于节省空间

    public class Solution {
        public static int bagProblemOp(int[] values, int[] weight, int capacity) {
            int[] dp = new int[capacity + 1];
            int len = values.length;
    
            for (int i = 1; i <= len; ++i) {
                // 遍历找到最大的收益价值
                for (int j = capacity; j >= 0; --j) {
                    if (weight[i - 1] <= j)
                        dp[j] = Math.max(
                                dp[j],
                                dp[j - weight[i - 1]] + values[i - 1]
                        );
                }
            }
    
            return dp[capacity];
        }
    }
    

标签:背包,capacity,weight,int,问题,values,物品,动态
来源: https://www.cnblogs.com/FatalFlower/p/15156315.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有