擬似多項式時間 とは何ですか?多項式時間とどう違うのですか?擬似多項式時間で実行される一部のアルゴリズムには、O(nW)( /1ナップザック問題 )またはO(√n)( trial division );なぜ多項式時間としてカウントされないのですか?
多項式時間と擬似多項式時間の違いを理解するには、「多項式時間」の意味を形式化することから始める必要があります。
多項式時間の一般的な直観は、「time O(nk)for some k。 "たとえば、 selection sort in time in O(n2)、これは多項式時間ですが、ブルートフォース解法 [〜#〜] tsp [〜#〜] は時間O(n・n!)を取りますが、これは多項式時間ではありません。
これらのランタイムはすべて、入力のサイズを追跡する変数nを参照します。たとえば、選択ソートでは、nは配列内の要素の数を指し、TSPではnはグラフ内のノードの数を指します。このコンテキストで「n」が実際に意味するものの定義を標準化するために、時間の複雑さの正式な定義は次のように問題の「サイズ」を定義します。
問題への入力のサイズは、その入力を書き出すのに必要なビット数です。
たとえば、ソートアルゴリズムへの入力が32ビット整数の配列である場合、入力のサイズは32nになります。nは配列内のエントリの数です。 n個のノードとm個のエッジがあるグラフでは、入力は、すべてのノードのリストとそれに続くすべてのエッジのリストとして指定できます。これには、Ω(n + m)ビットが必要です。
この定義を前提とすると、多項式時間の正式な定義は次のとおりです。
ランタイムがO(xの場合、アルゴリズムは多項式時間で実行されますk)定数kの場合、xはアルゴリズムに与えられた入力のビット数を示します。
グラフ、リスト、ツリーなどを処理するアルゴリズムを使用する場合、この定義は従来の定義とほぼ一致します。たとえば、32ビット整数の配列をソートするソートアルゴリズムがあるとします。選択ソートなどを使用してこれを行う場合、ランタイムは、配列内の入力要素の数の関数としてO(n2)。しかし、入力配列の要素数であるnは、入力のビット数にどのように対応しますか?前述のように、入力のビット数はx = 32nになります。したがって、アルゴリズムのランタイムをnではなくxで表現すると、ランタイムはO(x2)、したがってアルゴリズムは多項式時間で実行されます。
同様に、グラフで depth-first search を実行するとします。これには時間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年、3人のコンピューター科学者がPRIMESはPにありますと呼ばれる論文を発表し、数が素数かどうかをテストするための多項式時間アルゴリズムを提供しました。これは画期的な結果と見なされました。それで、大したことは何ですか?このための多項式時間アルゴリズム、つまり上記のものはすでにありませんか?
残念ながら、そうではありません。時間の複雑さの正式な定義は、アルゴリズムの複雑さについて語る入力のビット数の関数として。アルゴリズムは時間O(n4)、しかし、それは入力ビット数の関数として何ですか?さて、数字nを書き出すにはO(log n)ビットが必要です。したがって、入力nを書き出すのに必要なビット数をxとすると、このアルゴリズムの実行時間は実際にはO(24倍)、これはnot xの多項式です。
これは、多項式時間と疑似多項式時間の区別の中心です。一方では、アルゴリズムはO(n4)、これは多項式のように見えますが、一方で、多項式時間の形式的な定義では、多項式時間ではありません。
アルゴリズムが多項式時間アルゴリズムではない理由を直感的に理解するには、次のことを考えてください。アルゴリズムに多くの作業を行わせる必要があるとします。このような入力を書き出すと:
10001010101011
その後、T
などの最悪の場合に完了するまでに時間がかかります。次のように、数値の末尾にシングルビットを追加すると、
100010101010111
ランタイムは(最悪の場合)2Tになります。もう1ビット追加するだけで、アルゴリズムの作業量を2倍にできます。
アルゴリズムは、ランタイムがそれを表すのに必要なビット数ではなく、多項式入力の数値である場合、pseudopolynomial timeで実行されます。主要なテストアルゴリズムは、時間O(n4)、しかし、入力を書き出すのに必要なビット数xの関数として、ランタイムはO(24倍)。 「PRIMESがPに含まれている」という論文が非常に重要だった理由は、その実行時間が(おおよそ)O(log12 n)、ビット数の関数としてO(x12)。
なぜこれが重要なのでしょうか?さて、整数を因数分解するための多くの擬似多項式時間アルゴリズムがあります。ただし、これらのアルゴリズムは、技術的に言えば、指数時間アルゴリズムです。これは暗号化に非常に役立ちます。RSA暗号化を使用する場合は、数字を簡単に因数分解できないことを信頼できる必要があります。数値のビット数を巨大な値(たとえば、1024ビット)に増やすことで、擬似多項式時間因数分解アルゴリズムに要する時間が非常に長くなり、因数分解が完全に完全に実行不可能になる可能性があります。数字。一方、多項式-時間因数分解アルゴリズムを見つけることができる場合、これは必ずしもそうではありません。より多くのビットを追加すると、作業が大きく成長する可能性がありますが、成長は指数関数的成長ではなく、多項式成長のみです。
とはいえ、多くの場合、数値のサイズが大きくなりすぎないため、擬似多項式時間アルゴリズムは完全に問題ありません。たとえば、 counting sort には、実行時O(n + U)があります。ここで、Uは配列内の最大数です。これは擬似多項式時間です(Uの数値を書き込むにはO(log U)ビットが必要なため、ランタイムは入力サイズで指数関数的です)。 Uを人為的に制約してUが大きすぎないようにした場合(たとえば、Uを2にした場合)、ランタイムはO(n)になります。これは実際には多項式時間です。これが 基数ソート の仕組みです:数値を一度に1ビットずつ処理することにより、各ラウンドのランタイムはO(n)であるため、全体のランタイムはO(n log U)です。これは実際にis多項式時間です。ソートするn個の数値を書き込むとΩ(n)ビットが使用され、log Uの値は配列の最大値を書き込むのに必要なビット数に正比例します。
お役に立てれば!
擬似多項式時間の複雑度とは、入力の値/大きさは多項式ですが、入力のサイズは指数関数的であることを意味します。
サイズとは、入力の書き込みに必要なビット数を意味します。
ナップザックの擬似コードから、時間の複雑さは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は入力の長さが多項式ではありませんが、これが擬似多項式になります。
Sを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)
今、running time of knapsack
= O(nW) = O(n * 2 ^ s)これは多項式ではありません。