当前位置: 首页 > 知识库问答 >
问题:

0-1背包:在空间优化实现中找到解决方案集

谢俊力
2023-03-14

这里的一个明显问题是,对于我所考虑的维度,这种方法消耗的内存将超过可行的(需要O(n*w)空间,N是元素数,W是最大容量)。进一步研究,我发现提到了(例如,这里也参见Kellerer,Pferschy和Pisinger的“背包问题”)一个内存有效的方法来解决0-1背包。

我们首先将项目集合分成大小大致相等的两个子集。我们将这两个子集视为它们自己的背包问题,给定初始的最大权重w,并以节省内存的方式为这两个子集确定最大利润计算的最后一行(详见上文)。

下一步是找出在哪里最优地拆分这两个子集。为此,我们确定两行的重量W1W2的最大利润。据我所知,维护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]
split(weights[:s1], values[:s1], s1, c1, i)      
split(weights[s1:], values[s1:], s2, c2, i+s1)

这就是我失去描述的地方。最后,这段代码将递归到n==1,其值为w。在给定项索引I和最大(本地)容量w的情况下,如何确定是否包含元素?

我可以提供一个小的示例数据集来详细说明我的代码的工作方式以及哪里出错。非常感谢。

共有1个答案

景麒
2023-03-14

首先,我想您把CW和它们作为容量的关系说错了,但是从利润列表中获得C1C2

对于问题,通过分裂函数的返回值,您可以定义您正在回答的问题类型。

当您采用直接到n==1点的拆分,并且希望将所选项的索引获取到背包中时,只需在这一步返回由[0][1]组成的值作为输出:

if n == 1:
  if weights[0] < w:
    return [1]
  return [0]
  • [1]表示将项选入结果集
  • [0]否则

然后在split函数递归的其他步骤中将它们连接成一个,如下所示:

def split(..):
  ..
  # since it is lists concatenation
  return split(weights[:s1], values[:s1], s1, c1, i) + split(weights[s1:], values[s1:], s2, c2, i+s1)

结果,您将得到大小n的列表(表示拆分的项数),其中有0和1。

    null
 类似资料:
  • 我正在为即将到来的测试复习,想知道是否有人能重述问题的b部分。这是从分发的复习表中得到的文本,但我不确定b部分到底在问什么。我更直截了当地猜测“生成一个不到0/1背包问题最优值1%的解”是什么意思。 b)[10pts]举了一个有两个对象的例子,说明对分数背包问题使用的相同的贪婪方法(略加修改,如果贪婪方法选择的最后一个对象不适合,则忽略它)得到的解不到0/1背包问题最优解的1%。

  • 0/1背包动态规划算法的空间优化是使用大小等于背包容量的1-d数组(例如A),并在每次迭代i时简单地覆盖A[w](如果需要),其中A[w]表示如果考虑前i个项目并且背包容量为w,则总价值。如果使用这种优化,是否有办法重建选择的项目列表,也许通过在DP算法的每次迭代中保存一些额外信息?例如,在Bellman Ford算法中,可以实现类似的空间优化,并且只要我们保留前身指针的列表,即最后一跳(或第一跳

  • 给定一个值N,如果我们想换N美分,并且我们有无限量的S={S1,S2,…,Sm}值的硬币,我们可以用多少种方式来换?硬币的顺序无关紧要。 例如,对于N=4和S={1,2,3},有四种解:{1,1,1,1},{1,1,2},{2,2},{1,3}。所以输出应该是4。对于N=10和S={2,5,3,6},有五个解:{2,2,2,2},{2,2,3,3},{2,2,6},{2,3,5}和{5,5}。所以

  • 类似的问题是存在的,但没有一个答案受到关注.. 这里说“解决这个问题的一个方法是JDBC驱动程序由通用类加载器而不是应用程序类加载器加载,你可以通过将驱动程序的jar文件转移到tomcat lib中,而不是捆绑在web应用程序的war文件中 不明白通过通用类加载器加载意味着什么,它与应用程序类加载器有什么不同。

  • 我在这里编写了一个Python解决方案,它解决了以下问题:如何用最少数量的给定面额的硬币来制造给定数量的货币? 虽然我的解决方案有效,但当大于50或的长度大于5时,需要很长时间。我怎样才能加快代码的速度,使其能够在相当大的输入下工作?我是否错过了一个技巧或其他可以大大加快代码速度的东西?

  • 在维基百科中,背包的算法如下: 我在网上找到的所有例子的结构都是一样的<我无法理解的是,这段代码是如何考虑到最大值可能来自较小的背包这一事实的?E、 如果背包容量为8,那么最大值可能来自容量7(8-1)<我找不到任何逻辑来考虑最大值可能来自较小的背包。这是错误的想法吗?