如何理解背包问题是NP完全的?


79

我们知道,背包问题可以通过动态编程以O(nW)复杂度解决。但是我们说这是一个NP完全问题。我觉得在这里很难理解。

(n是项目数。W是最大音量。)


此法定答案使用的示例显示了非常清晰的理由,导致您对该主题产生矛盾和理解
DanSkeel 2015年

Answers:


44

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)

线性增加算法输入的大小是什么意思?这意味着使用越来越长的项目阵列(所以nn+1n+2,...),并逐渐变长W(所以,如果Wx位长,一步之后,我们使用x+1位,则x+2位,...)。但W与呈指数增长x,因此算法不是真正的多项式,它的指数(但看起来它是多项式,因此被命名为“伪多项式”)。


其他参考


2
有两种方法可以测量数字的大小。给定数字10和1000,您可以说1000的两倍(以字符数计)或一百倍。由于差异是指数的,因此您可以拥有一种算法,该算法针对数字幅度测量多项式,针对位数计算指数。
David Thornley,2010年

4
我完全看不到编码中的位数与此问题有任何关系。我确实了解位数是如何影响整数分解的复杂性的,因为单个整数是您的“输入”。但是,数字Wn此处表示循环迭代的次数。 您可以使用任何所需的方式对其进行编码,并且该循环仍将迭代n * W多次。我相信这个“​​伪多项式”的原因n是因为实际输入大小,并且W比实际输入大小大得多,n因此不能公平地将其视为常量。
The111 2013年

4
为了帮助您理解它:1)考虑一个for1到的循环nn输入在哪里);在这种情况下,当循环执行10 ^ 12次迭代时,输入的大小仍约为40位。迭代数量的增长速度快于对输入进行编码的位数。时间复杂度不是线性的。2)再次,考虑一个for循环,一个多输入阵列(与大小迭代n从)1n; 如果您有10 ^ 12次迭代,则意味着您的数组包含10 ^ 12个项目。迭代数量以与输入大小相同的速度增长。时间补全 是线性的。
Zsolt Safrany

4
@AkshayLAradhya如果我们考虑我的示例,那么我们只需在输入中多添加一点即可。这样,我们将迭代次数加倍(额外的10 ^ 12迭代),但是输入的长度仅增加了一个。接下来,我们将获得更多的迭代。等等。因此,“迭代次数增长快于[编码]输入所需的位数”,其中输入表示迭代次数。得到它了?:-)
Zsolt Safrany,2015年

2
让我点击的原因是,对于背包问题输入,n不是数字,而是实际的东西,而W是数字。您无法解决重量10和事物数6的背包问题。您实际上需要n成为事物...一个增长的数组。我们用数字表示n(事物数组)的SIZE的方式,但是用位表示W(数字)的SIZE的方式。
amoffat

24

在背包0/1问题中,我们需要2个输入(1个数组和1个整数)来解决此问题:

  1. n个项的数组:[n1,n2,n3,...],每个项都有其值索引和权重索引。
  2. 整数W作为最大可接受重量

假设n = 10且W = 8:

  1. n = [n1,n2,n3,...,n10]
  2. W =二进制形式的1000 (4位长)

所以时间复杂度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问题。


谢谢YoEugene,我终于明白了这一点!所以这里的意思是,复杂度实际上取决于输入大小,在这种情况下,复杂度是W的位长。当我们讨论检查数字N是否为素数时,同样的事情也会发生,输入实际上就是N的位长,因此,尽管我们采取了N步,复杂度为O(N),但它仍然是伪多项式。相反,如果我们尝试在长度为N的数组中找到一个数字,则输入实际上为N,因此O(N)的复杂度实际上是线性的。
yeelan

6

这完全取决于您放入的参数O(...)

如前所述W,如果目标重量受数量限制,那么问题就变得很O(n*W)复杂。

但是,如果权重太大,并且您需要的算法的复杂度与无关W,则问题是NP完全的。(O(2^n*n)在大多数幼稚的实现中)。


那么其他动态编程问题呢?例如,最长的公共子序列问题可以在O(L_1 * L_2)时间内解决吗?我们可以说它不是多项式吗?
cnhk 2010年

@cnhk似乎具有多项式复杂度O(n ^ 2)。但是有各种各样的DP算法,例如那些可以处理给定集合(2 ^ n个组合)的所有子集的算法,所以我不会说每个DP问题都可以在多项式时间内解决。
Nikita Rybak 2010年


3

输入的大小是log(W)权重的位(以及O(n)“值”和“权重”数组的位)。

因此,权重的输入大小为j = log(W)(而不仅仅是W)。因此,W = 2ʲ(使用二进制)。

最终的复杂度是 O(n * W)

O(n * W)可以被改写为O(n * 2ʲ),该指数在输入的大小。

因此,该解决方案不是多项式。



0

要了解NP完整性,您必须学习一些复杂性理论。但是,基本上,它是NP完全的,因为针对背包问题的有效算法也将成为SATTSP和其他算法的高效算法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.