什么是伪多项式时间?它与多项式时间有何不同?一些在伪多项式时间内运行的算法具有运行时,如O(nW)(用于0/1背包问题)或O(√n) (用于审判庭);为什么不算作多项式时间?
伪多项式时间复杂度意味着输入值/大小的多项式,但输入大小的指数。
我们所说的大小是指写入输入所需的位数。
从背包的伪码中,我们可以发现时间复杂度为O(nW)。
// Input:
// Values (stored in array v)
// Weights (stored in array w)
// Number of distinct items (n) //
Knapsack capacity (W)
for w from 0 to W
do m[0, w] := 0
end for
for i from 1 to n do
for j from 0 to W do
if j >= w[i] then
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i])
else
m[i, j] := m[i-1, j]
end if
end for
end for
这里,W在输入长度上不是多项式,这就是它是伪多项式的原因。
设为表示W所需的位数
i.e. size of input= s =log(W) (log= log base 2)
-> 2^(s)=2^(log(W))
-> 2^(s)=W (because 2^(log(x)) = x)
现在,背包的运行时间不是多项式。
要理解多项式时间和伪多项式时间之间的区别,我们需要从形式化“多项式时间”的含义开始。
多项式时间的常见直觉是“时间O(nk)对于某些k。”例如,选择排序在时间O(n2)中运行,这是多项式时间,而蛮力求解TSP需要时间O(n·n!),这不是多项式时间。
这些运行时都是指一些跟踪输入大小的变量n。例如,在选择排序中,n表示数组中的元素数,而在TSP中,n表示图中的节点数。为了标准化“n”在本文中的实际含义,时间复杂性的正式定义将问题的“大小”定义如下:
问题输入的大小是写入该输入所需的位数。
例如,如果排序算法的输入是一个32位整数数组,那么输入的大小将是32n,其中n是数组中的条目数。在一个有n个节点和m条边的图中,输入可以指定为所有节点的列表,然后是所有边的列表,这需要Ω(n m)位。
根据该定义,多项式时间的形式定义如下:
如果算法对于某个常数k的运行时间为O(xk),则该算法在多项式时间内运行,其中x表示给定给该算法的输入位数。
当使用处理图形、列表、树等的算法时,这个定义或多或少与传统定义一致。例如,假设你有一个排序算法,对32位整数的数组进行排序。如果你使用类似选择排序这样的东西来做到这一点,运行时作为数组中元素进审量的函数,将是O(n2)。但是n,输入数组中元素的数量,如何对应于输入的位数?如前所述,输入的位数将是x=32n。因此,如果我们用x而不是n表示算法的运行时,我们得到运行时是O(x2),因此算法以多项式时间运行。
类似地,假设在图上进行深度优先搜索,这需要时间O(m n),其中m是图中的边数,n是节点数。这与给定输入的位数有什么关系?好的,如果我们假设输入指定为邻接列表(所有节点和边的列表),那么如前所述,输入位数将为x=Ω(m n)。因此,运行时间将为O(x),因此算法在多项式时间内运行。
然而,当我们开始讨论对数字进行运算的算法时,情况就不一样了。让我们考虑一下测试一个数是否为素数的问题。给定一个数字n,可以使用以下算法测试n是否为素数:
function isPrime(n):
for i from 2 to n - 1:
if (n mod i) = 0, return false
return true
那么这段代码的时间复杂度是多少?好吧,这个内部循环运行O(n)次,每次都会做一些工作来计算n个mod i(作为一个非常保守的上限,这当然可以在时间O(n3)中完成)。因此,这个整体算法在时间O(n4)中运行,而且可能要快得多。
2004年,三位计算机科学家发表了一篇题为“素数在P中”的论文,提出了一种多项式时间算法来测试一个数是否为素数。这被认为是一个里程碑式的结果。那有什么大不了的?我们不是已经有了一个多项式时间算法吗,也就是上面的那个?
不幸的是,我们没有。记住,时间复杂度的形式定义讨论了算法的复杂度作为输入位数的函数。我们的算法在时间O(n4)内运行,但这是输入位数的函数吗?那么,写出数字n需要O(对数n)位。因此,如果我们让x是写出输入n所需的位数,则该算法的运行时间实际上是O(24x),这不是x中的多项式。
这是多项式时间和伪多项式时间之间区别的核心。一方面,我们的算法是O(n4),它看起来像一个多项式,但另一方面,在多项式时间的形式定义下,它不是多项式时间。
为了直观地了解该算法为什么不是多项式时间算法,请考虑以下几点。假设我想让算法做很多工作。如果我写出这样的输入:
10001010101011
然后需要一些最坏情况下的时间才能完成,例如T。如果我现在在数字的末尾添加一位,如下所示:
100010101010111
运行时现在(在最坏的情况下)是2T。我可以通过再增加一位来使算法的工作量翻倍!
如果运行时是输入数值中的某个多项式,而不是表示它所需的位数,则算法在伪多项式时间内运行。我们的主要测试算法是伪多项式时间算法,因为它在时间O(n4)中运行,但它不是多项式时间算法,因为作为写入输入所需位数x的函数,运行时间是O(24x)。“素数在P中”这篇论文之所以如此重要,是因为它的运行时间(大致)是O(log12n),它作为位数的函数是O(x12)。
那么为什么这很重要呢?我们有很多伪多项式时间算法来分解整数。然而,从技术上讲,这些算法是指数时间算法。这对于密码学非常有用:如果你想使用RSA加密,你需要能够相信我们不能轻松地计算数字。通过将数字中的位数增加到一个巨大的值(例如1024位),可以使伪多项式时间分解算法必须花费的时间量变得如此之大,以至于完全不可能对数字进行因子分解。另一方面,如果我们可以找到多项式时间因子分解算法,则不一定是这样。添加更多位可能会导致工作量大幅增加,但增长将仅为多项式增长,而不是指数增长。
也就是说,在许多情况下,伪多项式时间算法非常好,因为数字的大小不会太大。例如,计数排序的运行时为O(n U),其中U是数组中最大的数字。这是伪多项式时间(因为U的数值需要O(log U)位才能写出,所以运行时在输入大小中是指数级的)。如果我们人为地限制U,使U不会太大(例如,如果我们让U为2),那么运行时为O(n),实际上是多项式时间。这就是基数排序的工作原理:通过一次一位地处理数字,每轮的运行时间是O(n),所以总体运行时间是O(n log U)。这实际上是多项式时间,因为写出n个数字进行排序使用Ω(n)位,而log U的值与写出数组中最大值所需的位数成正比。
希望这有帮助!
我正试图为这个问题想出一个合理的算法: (例如,你可以把一个蓝色和绿色的球放进蓝色盒子或绿色盒子里,但不能放进红色盒子里。) 我做了一些研究,这似乎类似于背包问题,也类似于匈牙利算法可以解决的问题,但我似乎不能把它简化为任何一个问题。 我只是好奇,对于这种类型的问题,是否有某种动态规划算法,可以在多项式时间内求解,或者它只是变相的旅行商问题。如果我知道最多有X种颜色会有帮助吗?非常感谢任何帮助。如
本文向大家介绍多项式时间近似方案,包括了多项式时间近似方案的使用技巧和注意事项,需要的朋友参考一下 多项式时间近似方案 我们可以找到一些关于NP完全问题的多项式时间解,例如0-1背包问题或子集和问题。这些问题在现实世界中非常流行,因此必须有一些方法来解决这些问题。 多项式时间近似方案(PTAS)是一种用于优化问题的近似算法。对于0-1背包问题,有一个伪多项式解决方案,但是当值较大时,该解决方案不可
在讲座中,我们已经考虑了背包问题:有n个项的正权值为w1,..、wn和值v1,..vn和容量为W的背包。问题的可行解是使总重量不超过W的物品的子集。目标是找到一个最大可能总价值的可行解。对于权值均为正整数的情形,我们讨论了求解时间为O(nW)的背包问题的动态规划解法。 a)假设所有项目的权值都是正整数,而不是权值。项目的权值可以是任意的正实数。描述一个解决背包问题的动态规划算法,如果所有项目的值都
我在考虑换硬币时想到了以下问题,但我不知道一个有效的(伪多项式时间)算法来解决它。我想知道是否有任何伪多项式时间的解决方案,或者一些经典的文献,我遗漏了。 硬币变化问题有一个著名的伪多项式时间动态规划解决方案,它问以下问题: 取硬币仅此,将此硬币指定为具有值 取硬币仅此,将此硬币指定为具有值 取硬币和,将其赋值为具有值和,或和,它们分别被认为是相同的方式 取硬币,和,并将其赋值为具有值,和 我遇到
上篇的标记算法中,谈到这个O(K)的算法是一个指数级复杂度的算法,其实对那道题目本身来说,K是固定的,既然不是输入,那也无所谓复杂度,之所以有O(K)这种说法,是把K当做一种输入了,这是看待输入的角度问题,倒不用深究。考虑一个更简化的算法(python代码,设输入n是正整数): def f(n): i = 0 while i < n: i += 1
我已经实现了32位单精度浮点加法/减法、乘法、余弦、正弦、除法、平方根和范围缩小,所有这些都是在这个体系结构上的软件。 为了实现余弦和正弦,我首先使用了范围约简,使用了K.C.在论文“大参数的参数约简”中描述的方法。NG I然后实现了一个余弦和正弦函数,这是余弦和正弦函数在-pi/4到+pi/4范围内的多项式逼近。我参考了哈特等人的《计算机近似值》一书。对于多项式。 我也听说我应该考虑CORDIC