【发布时间】:2011-04-23 21:08:07
【问题描述】:
我们知道背包问题可以通过动态规划以 O(nW) 复杂度解决。但我们说这是一个 NP 完全问题。我觉得这里很难理解。
(n是项目数。W是最大体积。)
【问题讨论】:
-
This quora answer 使用的例子显示了非常清晰的推理,导致你对这个话题产生矛盾和理解
标签: algorithm complexity-theory
我们知道背包问题可以通过动态规划以 O(nW) 复杂度解决。但我们说这是一个 NP 完全问题。我觉得这里很难理解。
(n是项目数。W是最大体积。)
【问题讨论】:
标签: algorithm complexity-theory
O(n*W) 看起来像一个多项式时间,但它不是,它是pseudo-polynomial。
时间复杂度衡量算法所花费的时间,作为其输入的长度(以位为单位)的函数。动态规划解决方案确实在W 的值上是线性的,但在W 的长度上是指数的——这才是最重要的!
更准确地说,背包问题的动态解的时间复杂度基本上是由一个嵌套循环给出的:
// here goes other stuff we don't care about
for (i = 1 to n)
for (j = 0 to W)
// here goes other stuff
因此,时间复杂度显然是O(n*W)。
线性增加算法输入的大小是什么意思?这意味着使用越来越长的项目数组(所以n,n+1,n+2,...)和越来越长的W(所以,如果W是x位长,一步后我们使用x+1 位,然后是 x+2 位,...)。但是W的值随着x呈指数增长,因此该算法不是真正的多项式,它是指数的(但看起来它是多项式,因此得名:“伪多项式”) .
【讨论】:
W 和n 表示循环迭代次数。您可以按照自己的方式对它们进行编码,并且该循环仍将迭代n * W 次。我相信这个“伪多项式”的原因是因为n 是实际输入大小,而W 可能比n 大得多,因此不能公平地被视为一个常数。
1 到n 的for 循环(其中n 是输入);在这种情况下,当您的循环进行 10^12 次迭代时,输入的大小仍然约为 40 位。迭代次数的增长速度快于对输入进行编码的位数。时间复杂度不是线性的。 2) 再次考虑一个for 循环,该循环遍历从1 到n 的输入数组(大小为n);如果您有 10^12 次迭代,则意味着您的数组包含 10^12 个项目。迭代次数的增长速度与输入的大小相同。时间综合是线性的。
在背包 0/1 问题中,我们需要 2 个输入(1 个数组和 1 个整数)来解决这个问题:
假设 n=10 和 W=8:
所以时间复杂度 T(n) = O(nW) = O(10*8) = O(80)
如果你将 n 的大小加倍:
n = [n1, n2, n3, ... , n10] -> n = [n1, n2, n3, ... , n20]
所以时间复杂度 T(n) = O(nW) = O(20*8) = O(160)
但是当你将W的大小加倍时,这并不意味着W=16,而是长度会长一倍:
W = 1000 -> W = 10000000 二进制(8位长)
所以 T(n) = O(nW) = O(10*128) = O(1280)
所需时间呈指数增长,所以这是一个 NPC 问题。
【讨论】:
这完全取决于您在O(...) 中放入了哪些参数。
如果目标权重受数字W 的限制,那么问题就具有O(n*W) 的复杂性,正如您所提到的。
但是,如果权重太大并且您需要复杂度独立于W 的算法,那么问题就是 NP 完全的。 (O(2^n*n) 在最幼稚的实现中)。
【讨论】:
这是因为背包问题有一个伪多项式解,因此被称为weakly NP-Complete(而不是@ 987654322@)。
【讨论】:
权重的输入大小为log(W) 位(“值”和“权重”数组为O(n))。
所以,权重的输入大小是j = log(W)(而不仅仅是W)。所以,W = 2ʲ(使用二进制)。
最终复杂度为O(n * W)
这个
O(n * W)可以重写为O(n * 2ʲ),它是输入大小的指数。
所以,这个解不是多项式的。
【讨论】:
您可以阅读以下简短说明:The NP-Completeness of Knapsack。
【讨论】:
要理解NP-completeness,你必须学习一点复杂性理论。但是,基本上,它是 NP 完全的,因为背包问题的有效算法也将是 SAT、TSP 和其他问题的有效算法。
【讨论】: