我们知道,背包问题可以通过动态编程以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ʲ),该指数在输入的大小。
因此,该解决方案不是多项式。