疑似多項式時間とは何ですか?多項式時間とどう違うのですか?


100

疑似多項式時間とは何ですか?多項式時間とどう違うのですか?疑似多項式時間で実行される一部のアルゴリズムには、O(nW)(0/1ナップザック問題の場合)またはO(√n)(試行除算の場合)などのランタイムがあります。なぜそれが多項式時間として数えられないのですか?


回答:


253

多項式時間と疑似多項式時間の違いを理解するには、「多項式時間」の意味を形式化することから始める必要があります。

多項式時間の一般的な直感は、「いくつかのkの時間O(n k)」です。たとえば、選択ソートは多項式時間である時間O(n 2)で実行されますが、ブルートフォース解決TSPは多項式時間ではない時間O(n・n!)を要します。

これらのランタイムはすべて、入力のサイズを追跡する変数nを参照します。たとえば、選択ソートでは、nは配列内の要素の数を指し、TSPではnはグラフ内のノードの数を指します。この文脈で実際に「n」が何を意味するかの定義を標準化するために、時間の複雑さの正式な定義は、問題の「サイズ」を次のように定義します。

問題への入力のサイズは、その入力を書き出すために必要なビット数です。

たとえば、並べ替えアルゴリズムへの入力が32ビット整数の配列である場合、入力のサイズは32nになります。nは配列内のエントリの数です。n個のノードとm個のエッジを持つグラフでは、入力はすべてのノードのリストとして指定され、その後にすべてのエッジのリストが続きます。これにはΩ(n + m)ビットが必要です。

この定義を前提として、多項式時間の正式な定義は次のとおりです。

ある定数kに対してランタイムがO(x k)である場合、アルゴリズムは多項式時間で実行されます。ここで、xはアルゴリズムに与えられる入力のビット数を示します。

グラフ、リスト、ツリーなどを処理するアルゴリズムを使用する場合、この定義は多かれ少なかれ従来の定義と一致します。たとえば、32ビット整数の配列を並べ替える並べ替えアルゴリズムがあるとします。これを行うために選択ソートのようなものを使用する場合、ランタイムは、配列内の入力要素の数の関数として、O(n 2)になります。しかし、入力配列の要素数であるnは、入力のビット数にどのように対応するのでしょうか。前述のように、入力のビット数はx = 32nになります。したがって、アルゴリズムの実行時間をnではなくxで表すと、実行時間はO(x 2)となり、アルゴリズムは多項式時間で実行されます。

同様に、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(n 3)で実行できます)。したがって、この全体的なアルゴリズムは時間O(n 4)で実行され、おそらくはるかに高速です。

2004年、3人のコンピューターサイエンティストがPRIMESと呼ばれる論文を発表し、数値が素数かどうかをテストするための多項式時間アルゴリズムを提供しています。これは画期的な結果と見なされました。だから大したことは何ですか?このための多項式時間アルゴリズム、つまり上記のものはすでにありませんか?

残念ながら、私たちにはありません。時間の複雑さの正式な定義は、入力のビット数の関数としてのアルゴリズムの複雑さについて述べていることを覚えておいてください私たちのアルゴリズムは時間O(n 4)で実行されますが、入力ビット数の関数としてそれは何ですか?まあ、数nを書き出すにはO(log n)ビットが必要です。したがって、入力nを書き出すのに必要なビット数をxとすると、このアルゴリズムの実行時間は実際にはO(2 4x)であり、xの多項式ではありません

これは、多項式時間と疑似多項式時間の違いの中心です。一方では、アルゴリズムはO(n 4)であり、多項式のように見えますが、一方で、多項式時間の正式な定義では、多項式時間ではありません。

アルゴリズムが多項式時間アルゴリズムではない理由を直感的に理解するには、次のことを考えてください。アルゴリズムに多くの作業を行わせたいとしましょう。このような入力を書き出すと:

10001010101011

T完了するまでに最悪の場合、たとえば時間がかかります。次のように、数値の最後に1ビットを追加するとします

100010101010111

ランタイムは(最悪の場合)2Tになります。もう1つビットを追加するだけで、アルゴリズムが実行する作業量を2倍にできます。

ランタイムが入力を表すのに必要なビット数ではなく、入力の数値の多項式である場合、アルゴリズムは疑似多項式時間で実行されます。プライムテストアルゴリズムは、時間O(n 4)で実行されるため、疑似多項式時間アルゴリズムですが、入力を書き出すために必要なビット数xの関数として、ランタイムはOであるため、多項式時間アルゴリズムではありません。 (2 4x)。「PRIMESがPである」という論文が非常に重要だった理由は、そのランタイムが(おおよそ)O(log 12 n)であり、ビット数の関数としてO(x 12)であったためです。

では、なぜこれが問題になるのでしょうか。さて、整数を因数分解するための多くの疑似多項式時間アルゴリズムがあります。ただし、これらのアルゴリズムは、技術的には指数時間アルゴリズムです。これは暗号化に非常に役立ちます。RSA暗号化を使用する場合は、数値を簡単に因数分解できないことを信頼できる必要があります。数値のビット数を巨大な値(たとえば、1024ビット)に増やすことで、疑似多項式時間因数分解アルゴリズムにかかる時間を非常に大きくして、番号。一方、多項式時間因数分解アルゴリズムを見つけることができる場合、これは必ずしもそうではありません。より多くのビットを追加すると、作業が大幅に増加する可能性がありますが、増加は多項式の成長のみであり、指数関数的な成長ではありません。

とはいえ、多くの場合、数値のサイズが大きくなりすぎないため、疑似多項式時間アルゴリズムは完全に適切です。たとえば、ソートのカウントにはランタイムO(n + U)があり、Uは配列内の最大数です。これは疑似多項式時間です(Uの数値は書き出すためにO(log U)ビットを必要とするため、ランタイムは入力サイズで指数関数的です)。Uが大きすぎないようにUを人工的に制約する場合(たとえば、Uを2にすると)、ランタイムはO(n)になり、これは実際には多項式時間です。これが基数ソートの仕組みです。一度に1ビットずつ数値を処理することにより、各ラウンドのランタイムはO(n)になるため、全体的なランタイムはO(n log U)になります。これは実際 並べ替えにn個の数値を書き出すとΩ(n)ビットが使用され、log Uの値は配列の最大値を書き出すために必要なビット数に正比例するため、多項式時間。

お役に立てれば!


27
これがあるべきWikipediaの説明 ...
サンドロ・マイヤー

4
isPrimeの複雑度がO(n)ではなくO(n ^ 4)と推定されるのはなぜですか?わかりません。の複雑さn mod iがO(n ^ 3)でない限り、確かにそうではありません。
2016

4
@Nobody通常、2つの数値を変更するコストはO(1)と見なされますが、任意の大きな数値を扱う場合、乗算自体のコストは、数値自体のサイズの関数として増加します。非常に保守的になるように、私はO(n ^ 3)としてn未満の数値でmoddingを計算できると主張しました。
templatetypedef

1
@AndrewFlemming数値がメモリ内でどのように表現されるかによって異なります。数値を表すにはlog_2 nビットが必要な標準のバイナリ表現を使用していると想定していました。ただし、基になる表現を変更すると、入力のサイズの関数としてランタイムが変更されます。
templatetypedef

1
O(n ^ 3)の選択n mod iは非常に保守的です。のタイミングは、それ自体modnはなくのビット数の関数であるnため、O((log n)^ 3)である必要があります。
dasblinkenlight

2

疑似多項式の時間の複雑さは、入力の値/大きさでは多項式を意味しますが、入力のサイズでは指数関数的です。

サイズとは、入力を書き込むために必要なビット数を意味します。

ナップザックの疑似コードから、時間の複雑さは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)は多項式ではありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.