【问题标题】:Do you need to sort inputs for dynamic programming knapsack您是否需要对动态编程背包的输入进行排序
【发布时间】:2015-07-03 10:01:01
【问题描述】:

在我发现的每个使用动态编程的 1/0 背包问题的示例中,其中项目具有权重(成本)和利润,它从未明确表示要对项目列表进行排序,但在所有示例中它们都是排序的通过增加权重和利润(在示例中,权重越高利润越高)。所以我的问题是当从项目数组/列表中添加矩阵中的项目时,我可以按任何顺序添加它们,还是添加重量或利润最小的那个?因为从多个示例中我发现我不确定这是否只是巧合,或者您实际上每次都需要将最小的权重/利润放入矩阵中

【问题讨论】:

  • 不,对于背包问题,不需要对输入进行排序。如果它完成了,它只是为了说明解决方案。可以按任意顺序输入后尝试运行,结果应该是一样的。

标签: dynamic-programming knapsack-problem


【解决方案1】:

动态规划解决方案只不过是以有效的方式选择所有可能性(使用蛮力)(只需保存值以供将来参考)。

注意:我们考虑所有子集。即使列表已排序,子集的总数也将相同。所以最后所有的子集都会被考虑。

【讨论】:

    【解决方案2】:

    不,您不需要对权重进行排序,因为每一行都给出了该行权重限制下的最大可能值。最大值将出现在该行的最后一列。

    【讨论】:

      【解决方案3】:

      也许您正在寻找自下而上的动态解决方案。使用自下而上的方法求解动态求解有一个特点。

      第二种方法是自下而上的方法。这种方法通常取决于 关于子问题“大小”的一些自然概念,例如解决任何特定的问题 子问题仅取决于解决“较小”的子问题。我们排序 按大小排列子问题并按大小顺序解决它们,最小的在前。当解决一个 特定的子问题,我们已经解决了它的所有较小的子问题 解决方案取决于,我们已经保存了他们的解决方案。我们解决每个子问题 只有一次,当我们第一次看到它时,我们已经解决了它的所有问题 先决条件子问题。

      来自:算法简介,CORMEN(第 3 版)

      【讨论】:

        【解决方案4】:

        在这种情况下,“较小的问题”只是在可供选择的物品数量方面较小,而不是关于这些物品的利润或重量。如果给定一个 3 项列表,则子问题将是 2 项,并且有 1 项可供选择。

        首先对最小的问题进行硬编码(基本情况),然后在从小问题到大问题的每个阶段,枚举最佳利润,并选择最大值。最后,所有 2^n 组合都将被考虑,重复 max 的各个阶段将冒泡出最大的解决方案。

        更改输入顺序,或将主导项放入输入中(如更高的权重和更低的利润)可能只是改变 max() 的哪个参数在每个阶段获胜,但最终的最大结果将来自相同的项目选择,尽管在算法的不同阶段针对不同的排序顺序或输入特征进行选择。

        【讨论】:

          【解决方案5】:

          可以通过一些随机洗牌实验找到答案。 我发现是:升序更好。如果我错了,请纠正我。

          要点:https://gist.github.com/whille/39cf7bf8cf5dcf6ac933063735ae54de

          “算法设计”中描述的问题,ISBN:9780321295354,第 6.4 章。 可以使用两种方法:

          1. 正如所使用的章节,预先计算了一个M缓存,其中不需要子答案。
          2. 递归函数,易于理解和测试。我发现python3.5+的functools.cache可以用来检查需要多少子计算,正如我的要点所示:test_random()的升序是currsize中最小的,所以它是最有效的,并且可以扩展到浮点值.

          10 个随机重量(1~100)和 200 个 knapack 的结果:

          [(13.527716157276256,18.371888775465692),(16.18632175987168,206.88043031085252),(20.14117982372607,81.52793937986635),(33.28606671929836,298.8676699147799),(49.12968642850187,22.037638580809592),(55.279973594800225,377.3715225559507),(56.56103181962746,460.9161412820592),(60.38456825749498,10.721915577913244 ), (67.98836121062645, 63.47478755362385), (86.49436333909377, 208.06767811169286)]: 反向: 假 CacheInfo(命中=0, 未命中=832, maxsize=None, currsize=832) [(86.49436333909377,208.06767811169286),(67.98836121062645,63.47478755362385),(60.38456825749498,10.721915577913244),(56.56103181962746,460.9161412820592),(55.279973594800225,377.3715225559507),(49.12968642850187,22.037638580809592),(33.28606671929836,298.8676699147799),(20.14117982372607,81.52793937986635),( 16.18632175987168, 206.88043031085252), (13.527716157276256, 18.371888775465692)]: 反向: 真 CacheInfo(hits=0, misses=1120, maxsize=None, currsize=1120)

          方法2注意事项:

          1. 如果容量大得多,所有随机订单都具有相同的 currsize。
          2. N大时应避免调用堆栈溢出,因此应转换递归方法。通常可以使用两步方法,首先映射子问题依赖关系,然后计算。我稍后会尝试。

          【讨论】:

            猜你喜欢
            • 2011-02-05
            • 2011-01-03
            • 2021-03-16
            • 2014-08-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-05-29
            • 2018-11-30
            相关资源
            最近更新 更多