【发布时间】:2019-01-27 05:56:12
【问题描述】:
我想解决最大重量约为 200k 且元素超过 100k 的 0-1 背包问题,并最终确定项目集,而不仅仅是最佳重量。
在研究 0-1 背包时,我读到解决此问题的常用方法是通过动态规划并创建一个包含子问题的最佳解决方案的表格,从而将原始问题分成更小的部分,然后在表格上回溯以确定项目集。最大利润,不考虑所用物品,可以以一种内存有效的方式计算(如here 所述)。
这里明显的问题是,对于我想到的维度,这种方法会消耗比可行更多的内存(需要O(n*W) 空间,n 是元素数,W 是最大容量)。进一步研究后,我发现提到(例如,here,另见 Kellerer、Pferschy 和 Pisinger 的“背包问题”)一种解决 0-1 背包的内存有效方法。
我们首先将设置的项目分成两个子集,大小大致相等。在给定原始最大重量W 的情况下,我们将这两个子集视为它们自己的背包问题,并以节省内存的方式确定两个子集的最大利润计算的最后一行(详见上文)。
下一步是找出最佳分割两个子集的位置。为此,我们确定两行的重量w1 和w2 的最大利润。据我了解,维护w1 + w2 = W 至关重要,因此我遍历第一行并在当前索引的另一端获取索引。我当前对这一步的实现如下所示:
def split(weights, values, n, w, i):
# s1 is the bigger subset size if n is not even
s1 = n // 2 + (n&1)
s2 = n // 2
row1 = maximum_profit(weights, values, s1, w)
row2 = maximum_profit(weights[s1:], values[s1:], s2, w)
max_profits_for_capacity = [x + y for x, y in zip(row1, row2[::-1])]
max_profits = max(max_profits_for_capacity)
optimal_weight_index = max_profits_for_capacity.index(max_value)
c1 = row1[optimal_weight_index]
c2 = row2[w-optimal_weight_index-1]
c1 和c2 是每个子集的最大利润,然后保持c1 + c2 = W。使用这些值,我们递归到每个子集:
split(weights[:s1], values[:s1], s1, c1, i)
split(weights[s1:], values[s1:], s2, c2, i+s1)
这就是描述让我迷失的地方。最终,这段代码将递归到n == 1,值为w。给定项目索引i 和最大(本地)容量w,我如何确定是否包含元素?
我可以提供一个小的示例数据集来详细说明我的代码的工作原理以及出错的地方。非常感谢。
【问题讨论】:
标签: python combinatorics knapsack-problem