【问题标题】:How to understand the knapsack problem is NP-complete?如何理解背包问题是NP完全的?
【发布时间】:2011-04-23 21:08:07
【问题描述】:

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

(n是项目数。W是最大体积。)

【问题讨论】:

  • This quora answer 使用的例子显示了非常清晰的推理,导致你对这个话题产生矛盾和理解

标签: algorithm complexity-theory


【解决方案1】:

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)

线性增加算法输入的大小是什么意思?这意味着使用越来越长的项目数组(所以nn+1n+2,...)和越来越长的W(所以,如果Wx位长,一步后我们使用x+1 位,然后是 x+2 位,...)。但是W随着x呈指数增长,因此该算法不是真正的多项式,它是指数的(但看起来它是多项式,因此得名:“伪多项式”) .


进一步参考

【讨论】:

  • 有两种方法可以测量数字的大小。给定数字 10 和 1000,您可以说 1000 是两倍大(以字符数计)或一百倍。由于差异是指数的,因此您可以使用一种算法,它是根据数值幅度测量的多项式和根据位数测量的指数。
  • 我看不到编码中的位数与这个问题有任何关系。我确实了解位数如何影响整数分解的复杂性,因为单个整数是您的“输入”。但是,这里的数字Wn 表示循环迭代次数。您可以按照自己的方式对它们进行编码,并且该循环仍将迭代n * W 次。我相信这个“​​伪多项式”的原因是因为n 是实际输入大小,而W 可能比n 大得多,因此不能公平地被视为一个常数。
  • 为了帮助您理解它1) 考虑一个从1nfor 循环(其中n 是输入);在这种情况下,当您的循环进行 10^12 次迭代时,输入的大小仍然约为 40 位。迭代次数的增长速度快于对输入进行编码的位数。时间复杂度不是线性的。 2) 再次考虑一个for 循环,该循环遍历从1n 的输入数组(大小为n);如果您有 10^12 次迭代,则意味着您的数组包含 10^12 个项目。迭代次数的增长速度与输入的大小相同。时间综合是线性的。
  • @AkshayLAradhya 如果我们考虑我的示例,那么让我们在输入中添加一个额外的位。这样,我们将迭代次数加倍(额外的 10^12 次迭代),但输入的长度只增加了 1 次。随着下一个额外的位,我们将获得更多的额外迭代。等等。因此,“迭代次数的增长速度快于对输入进行编码所需的位数”,其中输入表示迭代次数。知道了? :-)
  • 让我点击的是,对于背包问题输入,n 不是数字,它是实际的东西,而 W 是数字。您无法解决重量为 10 且事物数量为 6 的背包问题。实际上您需要 n 成为事物……一个不断增长的数组。我们用数字表示 n(一个事物的数组)的 SIZE 的方式是用一个数字来表示 W(一个数字)的 SIZE 的方式是用位。
【解决方案2】:

在背包 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) 的复杂度实际上是线性的。
【解决方案3】:

这完全取决于您在O(...) 中放入了哪些参数。

如果目标权重受数字W 的限制,那么问题就具有O(n*W) 的复杂性,正如您所提到的。

但是,如果权重太大并且您需要复杂度独立于W 的算法,那么问题就是 NP 完全的。 (O(2^n*n) 在最幼稚的实现中)。

【讨论】:

  • 其他动态规划问题呢?例如,最长公共子序列问题可以在 O(L_1*L_2) 时间内解决吗?我们可以说它不是多项式吗?
  • @cnhk 看起来它具有多项式复杂度,O(n^2)。但是有各种各样的 DP 算法,例如处理给定集合的所有子集(2^n 组合)的算法,所以我不会说每个 DP 问题都可以在多项式时间内解决。
【解决方案4】:

这是因为背包问题有一个伪多项式解,因此被称为weakly NP-Complete(而不是@ 987654322@)。

【讨论】:

    【解决方案5】:

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

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

    最终复杂度为O(n * W)

    这个O(n * W) 可以重写为O(n * 2ʲ),它是输入大小的指数。

    所以,这个解不是多项式的。

    【讨论】:

      【解决方案6】:

      您可以阅读以下简短说明:The NP-Completeness of Knapsack

      【讨论】:

        【解决方案7】:

        要理解NP-completeness,你必须学习一点复杂性理论。但是,基本上,它是 NP 完全的,因为背包问题的有效算法也将是 SATTSP 和其他问题的有效算法。

        【讨论】:

          猜你喜欢
          • 2011-09-09
          • 2010-09-23
          • 1970-01-01
          • 2022-07-21
          • 2010-09-13
          • 2011-11-14
          • 2011-10-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多