【发布时间】:2019-03-31 00:12:48
【问题描述】:
我无法理解这种幼稚的递归解决方案如何以及为何起作用。如果我是第一次遇到这个问题,我会考虑对所有可能的组合进行详尽的搜索(迭代地),最后记录并返回最大值。有人可以解释一下这个解决方案吗?
来自 CSDojo 的代码
【问题讨论】:
标签: algorithm recursion dynamic-programming knapsack-problem
我无法理解这种幼稚的递归解决方案如何以及为何起作用。如果我是第一次遇到这个问题,我会考虑对所有可能的组合进行详尽的搜索(迭代地),最后记录并返回最大值。有人可以解释一下这个解决方案吗?
来自 CSDojo 的代码
【问题讨论】:
标签: algorithm recursion dynamic-programming knapsack-problem
此解决方案有效,因为逻辑合理。让我们把这个逻辑写成文字:
容量C 的最大值,使用第一项到nth 项中的任何一项:
def KS(n, C):
如果我们没有使用任何物品或者我们没有容量,那么我们的价值为零:
If n == 0 or C == 0:
result = 0
否则,如果此(nth)项目的重量大于此容量(C),则使用我们在此容量(C)没有此项目时可以获得的最佳结果。这就是Max value for capacity C, using any of the first to (n-1)th items 的解决方案(请记住,当前计算正在寻找KS(n, C),因此我们不允许使用列表中nth 之后的任何项目):
else if w[n] > C:
result = KS(n - 1, C)
否则,让我们决定是否应该使用这个项目:
else:
如果我们不使用nth 项,这与我们之前的可能性相同:Max value for capacity C, using any of the first to (n-1)th items 的解决方案:
tmp1 = KS(n - 1, C)
如果我们确实使用它,由于当前计算正在寻找容量 C 的解决方案,让我们将当前值 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 * C 不同的参数组合。这就是为什么一些递归,比如背包,经常被列成对n和C的迭代(例如嵌套的for循环)。
【讨论】:
此方法可能会执行穷举搜索。
它是分支和边界启发式的实现,其中 if 条件会切断当前分支,因为它不能进一步增长。
如果没有切割算法为所有可能的子集构建完整的二叉树(tmp1 和 tmp2 是选择 - 我们是否使用当前项目)
【讨论】:
该解决方案基本上尝试将项目n 放入(仅当它仍然适合时)或将其排除在外,然后尽可能好地放入剩余的项目(递归调用)。这给出了两个值 tmp1 和 tmp2。然后取其中的最大值。
【讨论】: