我们知道,背包问题可以通过动态编程以O(nW)复杂度解决。但是我们说这是一个NP完全问题。我觉得在这里很难理解。
(n是项目数。W是最大音量。)
Answers:
O(n*W)
看起来像多项式时间,但不是,它是伪多项式。
时间复杂度衡量算法所花费的时间与输入长度的函数关系。动态编程解决方案的值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
因此不能公平地将其视为常量。
for
从1
到的循环n
(n
输入在哪里);在这种情况下,当循环执行10 ^ 12次迭代时,输入的大小仍约为40位。迭代数量的增长速度快于对输入进行编码的位数。时间复杂度不是线性的。2)再次,考虑一个for
循环,一个多输入阵列(与大小迭代n
从)1
到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)
在大多数幼稚的实现中)。
输入的大小是log(W)
权重的位(以及O(n)
“值”和“权重”数组的位)。
因此,权重的输入大小为j = log(W)
(而不仅仅是W
)。因此,W = 2ʲ
(使用二进制)。
最终的复杂度是 O(n * W)
这
O(n * W)
可以被改写为O(n * 2ʲ)
,该指数在输入的大小。
因此,该解决方案不是多项式。