【算法(四·一):动态规划思想——0-1背包问题】

这篇具有很好参考价值的文章主要介绍了【算法(四·一):动态规划思想——0-1背包问题】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

算法介绍

0-1背包问题是一个经典的组合优化问题,通常用于描述以下情境:①有一个容量有限的背包,可以容纳一定总重量的物品。②有一组不同的物品,每个物品都有一个特定的重量和一个价值。③目标是在限定的背包容量内,选择一些物品放入背包,以使这些物品的总重量不超过背包容量,同时使它们的总价值最大化。
0-1背包问题的名称来自于每个物品在解中要么被完全放入背包(0表示不放入,1表示放入),而不允许将物品部分放入背包。它是一个NP难问题,没有一个多项式时间的精确解法,因此通常使用动态规划、贪心算法或启发式算法等近似方法来解决。其中,动态规划是解决0-1背包问题最常见且最有效的方法

问题描述

给定一组不同的物品,每个物品具有两个属性:重量(weight)和价值(value)。同时,有一个容量有限的背包,容量为W。问题的目标是确定如何选择这些物品放入背包,以使它们的总重量不超过W,并且总价值最大。

问题特点

  • 每个物品要么被放入背包(选中),要么不放入背包(不选中),不能部分选择。
  • 每个物品只能使用一次。
  • 物品的数量和容量都是有限的。
  • 目标是最大化背包中物品的总价值。

数学描述

  • 物品集合:{物品1, 物品2, …, 物品N},其中N是物品的数量。
  • 物品重量:{weight[1], weight[2], …, weight[N]},表示每个物品的重量。
  • 物品价值:{value[1], value[2], …, value[N]},表示每个物品的价值。
  • 背包容量:W。

问题目标

找到一个物品的选择方式,即一个0-1向量 {x1, x2, …, xN},其中xi为0或1,表示物品i是否被选中,以使得以下条件成立:

  • Σ(xi * weight[i]) ≤ W,总选择的物品重量不超过背包容量。
  • 最大化 Σ(xi * value[i]),总选择的物品价值最大化。

算法步骤

  • 问题结构分析

    • 明确原始问题:给定一组物品,每个物品都有一个重量 weight[i] 和一个价值 value[i],以及一个容量有限的背包,容量为 W。
    • 给出问题表示:我们定义的子问题是这样的,考虑前 i 个物品,背包容量为 w 时的最大总价值,表示为 dp[i][w]。
  • 递推关系建立

    • 分析最优(子)结构:以选和不选着手找到重叠子问题。

      假设我们已经解决了一个子问题 dp[i][w],它表示在考虑前 i 个物品和背包容量为 w 时的最大总价值。现在,我们考虑如何构建原问题 dp[N][W] 的最优解。

      • 如果我们不选择放入第 i 个物品,那么最优解就是 dp[i-1][w],即考虑前 i-1 个物品时背包容量为 w 时的最大总价值。
      • 如果我们选择放入第 i 个物品,那么最优解就是 dp[i-1][w - weight[i]] + value[i],即考虑前 i-1 个物品时背包容量为 w - weight[i] 时的最大总价值,再加上第 i 个物品的价值 value[i]。

      最优子结构的关键在于,无论我们选择放入还是不放入第 i 个物品,原问题 dp[N][W] 的最优解都可以通过子问题的最优解构建而来。这是动态规划的核心特性之一,允许我们使用递推关系将原问题分解成子问题,逐步求解最优解。

    • 构造递推公式

      • 递推关系(基于最优子结构而来)
        • 对于 i > 0 和 w > 0,dp[i][w] 可以按照以下递推关系更新:
          dp[i][w] = max(dp[i-1][w], dp[i-1][w - weight[i]] + value[i])
  • 自底向上计算

    • 确定计算顺序(通过递推式确定计算顺序)

      • 状态初始化:将初始化的条件搞定

        • 对于 i = 0,没有物品可选,所以对于所有 w,dp[i][w] = 0 。
        • 对于 w = 0,背包容量为0,所以对于所有 i, dp[i][w] = 0 。
          0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划
      • 明确子问题依赖关系

        • 子问题dp[i][w]依赖于子问题 dp[i-1][w-weight[i]]与dp[i-1][w]
          0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划

          dp[i-1][w-weight[i]]与dp[i-1][w]位于dp[i][w]的左上方,故每一行计算都需要把它的上一行算好。

    • 依次求解问题
      构造一个备忘录(二维数组 dp )存储子问题的解。从 i=0 到 N(物品的数量),以及从 w=0 到 W(背包容量),按照递推关系依次填充 dp 数组。这是一个自底向上的过程,确保每个子问题都依赖于前面的子问题的解。
      0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划

  • 最优方案追踪
    最优方案追踪是指在动态规划中找到原问题的最优解,即确定如何选择物品以使总价值最大,同时不超过背包容量。这通常涉及到从填充完动态规划表格后的某个特定单元格开始,然后根据填充过程中的决策来重建最优解。

    • 从动态规划表格中找到最终状态,即 dp[N][W],其中 N 表示物品的数量,W 表示背包的容量。这个单元格包含了问题的最优解,即最大的总价值。
    • 从 dp[N][W] 开始,向前追踪。设当前状态为 dp[i][w],其中 i 表示当前考虑的物品,w 表示当前剩余的背包容量。
    • 比较 dp[i][w] 与 dp[i-1][w] 是否相等。如果它们相等,表示当前物品 i 没有被选择放入背包。在这种情况下,继续向上追踪,即令 i 减小 1,不做任何标记。
    • 如果 dp[i][w] 与 dp[i-1][w] 不相等,说明当前物品 i 被选择放入背包。在这种情况下,将物品 i 标记为被选中,同时减少背包容量 w,即 w = w - weight[i]
    • 重复上述步骤,直到回到初始状态 dp[0][0],或者 i 等于 1。此时,你已经找到了构成最优解的物品的集合。
    • 最后,被标记为被选中的物品组成的集合就是问题的最优解,它们的总重量不超过背包容量 W,总价值最大化。

算法伪代码

这个伪代码描述了0-1背包问题的动态规划算法。算法通过填充一个二维数组 dp 来计算最大总价值,然后使用 traceSolution 函数来回溯找到选中的物品。注意,这个伪代码是一种通用框架,具体的数据结构和输入数据需要根据实际情况进行调整。

函数 knapsack(items, capacity):
    n = 数组 items 中物品的数量
    创建一个二维数组 dp,大小为 (n+1) x (capacity+1)

    对于 i 从 0 到 n:
        对于 w 从 0 到 capacity:
            如果 i=0 或 w=0:
                dp[i][w] = 0  # 基本情况,没有物品或者背包容量为0时,总价值为0
            否则如果 items[i-1].weight > w:
                dp[i][w] = dp[i-1][w]  # 当前物品过重,无法放入背包
            否则:
                # 考虑将当前物品放入背包和不放入背包两种情况,选择总价值更大的
                dp[i][w] = max(dp[i-1][w], items[i-1].value + dp[i-1][w-items[i-1].weight])

    返回 dp[n][capacity] 作为最大总价值

函数 traceSolution(items, dp, capacity):
    n = 数组 items 中物品的数量
    创建一个空数组 selectedItems
    w = capacity

    对于 i 从 n 到 1(倒序):
        如果 dp[i][w] ≠ dp[i-1][w]:
            # 当前物品被选中,将其添加到选中的物品列表,并更新背包容量
            将 items[i-1] 添加到 selectedItems
            w = w - items[i-1].weight

    返回 selectedItems 作为选中的物品列表

主程序:
items = 一组物品,每个物品包括 weight(重量)和 value(价值)
capacity = 背包的容量

最大总价值 = knapsack(items, capacity)
选中的物品 = traceSolution(items, dp, capacity)

算法实例

实例介绍

超市允许顾客使用一个体积大小为13的背包,选择一件或多件商品带走。问题:如何带走总价最多的商品?
0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划

实例分析

为了方便大家体会动态规划思想的解题步骤中符号的作用,本实例中我换一个符号来表示问题。大家自行体会。

  • 问题结构分析
    • 明确原始问题
      𝑷[𝒊, 𝒄]:前𝒊个商品可选、背包容量为𝒄时的最大总价格。
    • 给出问题表示
      𝑷[𝒏, 𝑪] :前𝒏个商品可选、背包容量为𝑪时的最大总价格。
  • 递推关系建立
    • 分析最优子结构0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划
    • 构造递推公式
      𝑷[𝒊, 𝒄] = 𝐦𝐚𝐱{𝑷[𝒊 − 𝟏, 𝒄] , 𝑷[𝒊 − 𝟏, 𝒄 − 𝒗𝒊] + 𝒑𝒊}
  • 自底向上计算
    • 确定计算顺序
      • 状态初始化

        • 容量为0时:𝑷[𝒊, 𝟎] = 𝟎
        • 没有商品时:𝑷[𝟎 , 𝒄] = 𝟎
          0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划
      • 明确子问题依赖关系
        𝑷[𝒊, 𝒄]依赖于子问题𝑷[𝒊 − 𝟏, 𝒄 − 𝒗𝒊]和𝑷[𝒊 − 𝟏, 𝒄]
        0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划

      • 计算顺序结果
        0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划

    • 依次求解子问题
      0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划
      0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划
      0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划

      0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划

      0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划

      0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划

      0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划
      …以此类推
      0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划
  • 最优方案追踪
    0-1背包问题是每个物品必须要么全放,要么都不放么,算法,动态规划
    • 从总价值最大P[5,13]=28入手,28不等于P[4,13]=26,故第5个商品被选,剩余背包体积13-4=9。我没要看P[4,9]。
    • P[4,9]=19不等于P[3,9]=11,故第4个商品被选,剩余背包体积9-5=4。我没要看P[3,4]。
    • P[3,4]=9不等于P[2,4]=2,故第3个商品被选,剩余背包体积4-4=0。此时背包空间为0,追踪结束。
    • 最终结果选了商品5、4、3。

算法性能

时间复杂度

在动态规划中,我们填充一个二维的 dp 表格,其中有 N 行(物品数量)和 W 列(背包容量)。每个单元格需要计算一次,而计算每个单元格的时间复杂度为常数时间。因此,0-1背包问题的动态规划算法的时间复杂度为 O(N*W)。

空间复杂度

动态规划算法需要一个二维数组来存储子问题的解,因此空间复杂度为 O(N*W)。这可能在某些情况下占用大量内存,特别是当物品数量和背包容量非常大时。

稳定性

检查算法在不同输入情况下的性能是否一致。算法应该对不同问题实例的输入数据表现稳定,而不会因输入的变化而导致不稳定的结果。

算法总结

总的来说,动态规划算法对于解决0-1背包问题是一种非常有效的方法,尤其适用于中小规模的问题。对于非常大的规模问题,时间和空间复杂度可能会变得不可行。因此在处理大规模问题时,需要谨慎考虑性能和可行性。算法的实际效果也受到问题特性和硬件环境的影响。文章来源地址https://www.toymoban.com/news/detail-789495.html

到了这里,关于【算法(四·一):动态规划思想——0-1背包问题】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ DP算法,动态规划——背包问题(背包九讲)

    有N件物品和一个容量为 V V V 的背包。放入第i件物品耗费的空间是 C i C_i C i ​ ,得到的价值是 W i W_i W i ​ 。 求解将哪些物品装入背包可使价值总和最大。 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。 用子问题定义状态:即 F [ i , v ] F[i, v] F

    2024年02月16日
    浏览(47)
  • 【算法(四·三):动态规划思想——最长公共子序列问题】

    最长公共子序列(Longest Common Subsequence,简称LCS)问题是一种常见的字符串处理问题。它的**目标是找到两个或多个字符串中的最长公共子序列,这个子序列不需要是连续的,但字符在原始字符串中的相对顺序必须保持一致。**例如,考虑两个字符串\\\"ABCD\\\"和\\\"ACDF\\\",它们的最长公

    2024年04月13日
    浏览(48)
  • 【动态规划】01背包问题——算法设计与分析

    若超市允许顾客使用一个体积大小为13的背包,选择一件或多件商品带走,则如何选择可以使得收益最高? 商品 价格 体积 啤酒 24 10 汽水 2 3 饼干 9 4 面包 10 5 牛奶 9 4 0-1 Knapsack Problem 输入: quad - n n n 个商品组成集合 O O O ,每个商品有属性价格 p i p_i p i ​ 和体积 v i v_i v

    2024年02月04日
    浏览(75)
  • acwing算法基础之动态规划--背包问题

    (零) 背包问题描述:有 N N N 个物品,每个物品的体积是 v i v_i v i ​ ,价值是 w i w_i w i ​ ,现有容量是 V V V 的背包,求这个背包能装下的物品的最大价值。 01背包问题:每个物品只有1个。 完全背包问题:每个物品有无穷多个。 多重背包问题:第 i i i 个物品有 s i s_i s

    2024年02月05日
    浏览(45)
  • 背包问题算法全解析:动态规划和贪心算法详解

    计算机背包问题是动态规划算法中的经典问题。本文将从理论和实践两个方面深入探讨计算机背包问题,并通过实际案例分析,帮助读者更好地理解和应用该问题。 背包问题是一种经典的优化问题。有的时候我们需要将有一堆不同重量或者体积的物品放入背包,但是背包容量

    2024年02月09日
    浏览(49)
  • 贪心算法解决背包问题和动态规划解决0-1背包问题(c语言)

    运行结果如下: 运行结果如下: 总结: 贪心算法: 每一步都做出当时看起来最佳的选择,也就是说,它总是做出局部最优的选择。 贪心算法的设计步骤: 对其作出一个选择后,只剩下一个子问题需要求解。 证明做出贪心选择后,原问题总是存在最优解,即贪心选择总是安

    2024年02月04日
    浏览(53)
  • 算法套路十四——动态规划之背包问题:01背包、完全背包及各种变形

    如果对递归、记忆化搜索及动态规划的概念与关系不太理解,可以前往阅读算法套路十三——动态规划DP入门 背包DP介绍:https://oi-wiki.org/dp/knapsack/ 0-1背包:有n个物品,第i个物品的体积为w[i],价值为v[i],每个物品至多选一个, 求体积和不超过capacity时的最大价值和,其中i从

    2024年02月10日
    浏览(55)
  • 算法分析与设计——动态规划求解01背包问题

    假设有四个物品,如下图,背包总容量为8,求背包装入哪些物品时累计的价值最多。 我们使用动态规划来解决这个问题,首先使用一个表格来模拟整个算法的过程。 表格中的信息表示 指定情况下能产生的最大价值 。例如, (4, 8)表示在背包容量为8的情况下,前四个物品的最

    2024年02月04日
    浏览(65)
  • 【Python算法】实验8-动态规划与背包问题

    目录 实验内容 1.数塔dp -A 2.骨牌铺方格 3.一只小蜜蜂

    2023年04月19日
    浏览(66)
  • 【Python算法】实验12-动态规划与背包问题

    目录 实验内容 1.数塔dp -A 2.骨牌铺方格 3.一只小蜜蜂

    2024年02月15日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包