背包问题-递归解决方案说明

时间:2018-10-26 09:08:16

标签: algorithm recursion dynamic-programming knapsack-problem

我无法理解这种幼稚的递归解决方案的工作方式和原因。如果是初次遇到此问题,我想考虑使用所有可能的组合(反复)进行详尽的搜索,最后记录并返回最大值。有人可以解释一下该解决方案吗?

code from CSDojo

来自Csjo的代码

3 个答案:

答案 0 :(得分:1)

此解决方案有效,因为逻辑是合理的。让我们把这种逻辑写成文字:

容量C的最大值,使用第一个n项:

def KS(n, C):

如果我们不使用任何物品或没有容量,那么我们的值为零:

If n == 0 or C == 0:
  result = 0

否则,如果第(n个项目的重量大于此容量(C),请使用我们可以为此容量获得的最佳结果(C),而不用这个项目。这是Max value for capacity C, using any of the first to (n-1)th items的解决方案(请记住,当前计算正在寻找KS(n, C),因此我们不允许在列表中第n之后使用任何项目)

else if w[n] > C:
  result = KS(n - 1, C)

否则,让我们决定是否应使用此项目:

else:

如果我们不使用第n条,则与我们先前的可能性相同:Max value for capacity C, using any of the first to (n-1)th items的解决方案:

  tmp1 = KS(n - 1, C)

如果确实使用它,由于当前计算正在寻找容量C的解决方案,因此,我们可以使用以前的{{1}中的任何一个,将当前值v[n]添加到我们的解决方案中}项,但容量为n-1,因此,与当前权重C - current_weight一起,我们将展示仍保留容量w[n]的解决方案:

C

选择较高的值:

  tmp2 = v[n] + KS(n - 1, C - w[n])

返回我们当前参数的正确结果:

  result = max{ tmp1, tmp2 }

递归可能有点违反直觉。调用return result 会产生大量对“较早”参数KS(n, C)n - 1等的调用,并且容量较低,这使得这些调用似乎在之后发生初始通话。但是实际上n - 2正在等待所有这些操作完成才能回答自己的计算,因此我们可以准确地说出它是在“更早的”参数调用之后发生的。当参数值重合时,它们中的许多可能会重复出现,这就是为什么对它们进行缓存以加快例程效率的原因。

KS(n, C)视为公式的“搜索空间”也很有用。这意味着我们实际上仅限于n, C不同的参数组合。这就是为什么某些递归(例如背包)经常被列表为n * Cn上的迭代(例如嵌套C循环)的原因。

答案 1 :(得分:0)

此方法可能会执行详尽搜索。

这是分支和边界启发法的实现,其中if-condition限制了当前分支,因为它无法进一步增长。

如果没有这种切割算法,则会为所有可能的子集(tmp1和tmp2是选择-我们是否使用当前项目)构建完整的二叉树

答案 2 :(得分:0)

该解决方案基本上是尝试将项目n放入(仅在仍适合的情况下)或将其丢弃,然后尽可能多地放入其余项目(递归调用)。这给出了两个值tmp1和tmp2。然后,它将使用其中的最大值。