有重复的背包 - 数组解决方案

Posted

技术标签:

【中文标题】有重复的背包 - 数组解决方案【英文标题】:Knapsack with repetition - array solution 【发布时间】:2015-04-24 04:28:21 【问题描述】:

我正在尝试理解课堂上给我的背包算法,特别是以下伪代码。

这是我尝试编写的代码:

//Init array
var solution = [];
var items = problem.items;
var sackSize = problem.knapsack;

solution[0] = 0;
for(var k = 1; k <= sackSize; k++)

    var loot = 0;
    for(var i = 1; i <= items.length; i++)
    
        if(k >= items[i].weight)
        
            loot = Math.max(loot, items[i].value)
        
    
    solution[k] = loot;

这对我来说没有意义,因为if(k &gt;= items[i].weight) 在循环的最后一次迭代中总是给出“索引越界”错误。 items 数组从索引 0 开始,但 i 从 1 开始。为什么我们从索引 1 开始?我是否误解了变量?

我得到了:

对象问题包括背包的最大重量 (problem.knapsack) 和一系列可用项目 (problem.items)。 每个项目都是一个具有重量和价值属性的对象 (problem.items[i].weight 和problem.items[i].value)。这两个 函数应该返回一个选定项目的数组。中的项目 返回的数组也应该有 weight 和 value 属性。

【问题讨论】:

在伪代码中从1 迭代到n 而不是0n-1 是很常见的。仅仅因为伪代码从1 迭代到n 并不意味着你的代码也必须从1 迭代到n,尤其是当你知道数组索引从0 开始时。 @wookie919 那么你认为解决方案不依赖于从 1 开始的它吗? 【参考方案1】:

您想查看items 数组的每个元素。第一个元素是items[0],最后一个元素是items[items.length-1]

因此,你应该换行

    for (var i = 1; i <= items.length; i++)

到这里:

    for (var i = 0; i < items.length; i++)

现在items[i].weight 将在最后一次迭代中有效。

那么为什么伪代码会这样说呢?

    for (i = 1; i <= n; i++) 

嗯,伪代码使用数学约定,其中项目从 1 到 n 编号。您的代码有不同的约定,其中项目的编号从 0items.length-1

这不是您的代码和伪代码之间的唯一区别。例如,您写的是k &gt;= items[i].weight 而不是k ≥ W[i]。此外,您正在使用 var 表示法声明局部变量。那是因为您的代码是一个实际的实现。伪代码是一种数学抽象。

伪代码中的抽象思想是逐个查看项目,在数学上表示为考虑W[1]W[n]。在您的代码中,第一项是items[0],最后一项是items[items.length-1]。您必须相应地编写for 语句。

啊,但是背包容量呢?我们是否也必须更改该循环索引?答案是不。在这里,我们正在处理具有不同含义的不同索引。我们不是在数组中查找项目,而是创建一个新数组,我们希望使用从 0 到 sackSize 的值进行索引。 solution[k] 的值是容量为k 的背包的最佳包装。

为了清楚起见,我建议您像这样声明solution 数组:

var solution = new Array(sackSize+1);

顺便说一句,作业要求你做的比伪代码做的更多。伪代码仅计算您可以通过最佳包装获得的总值。该作业要求您返回用于最佳包装的一组物品。

【讨论】:

查看我写的代码loot = Math.max(loot, items[i].value),但该行的伪代码有点复杂。不知道我是否错过了那个或什么,但我应该做更复杂的吗? 是的,这是正确计算解所必需的。 loot = Math.max(loot, items[i].value + solution[k - items[i].weight]); 如果有无数个相同的对象怎么办。如何解决? @Bear - 您可以将当前的if 语句替换为迭代变量的for 循环,比如count,表示i 类型的项目数。只要项目符合k(当前背包限制),就继续增加count。整个循环看起来像这样:for (var count = 1; count * items[i].weight &lt;= k; ++count) loot = Math.max(loot, count * items[i].value + solution[k - count * items[i].weight]);

以上是关于有重复的背包 - 数组解决方案的主要内容,如果未能解决你的问题,请参考以下文章

背包输出方案数

在实施与经典 0-1 背包类似情况的解决方案时重复项目

P1450 [HAOI2008]硬币购物(完全背包+容斥)

无重复背包与有重复背包的不同应用

动态规划解决背包问题

01背包动态规划