Warum ist das Rucksackproblem pseudo-polynomisch?

87

Ich weiß, dass Knapsackdas NP-vollständig ist, während es von DP gelöst werden kann. Sie sagen, dass die DP-Lösung ist pseudo-polynomial, da sie in der "Länge der Eingabe" exponentiell ist (dh die Anzahl der Bits, die zum Codieren der Eingabe erforderlich sind). Leider habe ich es nicht verstanden. Kann pseudo-polynomialmir jemand das langsam erklären ?

Michael
quelle

Antworten:

90

Die Laufzeit ist O (NW) für einen unbeschränkten Knapsackproblems mit N Artikeln und Tornister der Größe W. W in der Länge des Eingangs nicht Polynom ist aber, das ist , was es macht Pseudo -polynomial.

Betrachten Sie W = 1.000.000.000.000. Es werden nur 40 Bits benötigt, um diese Zahl darzustellen, also Eingabegröße = 40, aber die Rechenlaufzeit verwendet den Faktor 1.000.000.000.000, der O (2 40 ) ist.

Die Laufzeit wird also genauer als O (N.2 Bits in W ) bezeichnet, was exponentiell ist.

Siehe auch:

Moinudin
quelle
1
Link Nr. 3, der sich auf "Komplexität der dynamischen Programmierung für das 0-1-Rucksackproblem" bezieht, ist tot.
dev_nut
1
Entschuldigung, ich habe es nicht verstanden. Nehmen wir an, wir haben einen Algorithmus mit der Zeitkomplexität O (N), dann haben wir O (2 ^ (Bits in N)), was exponentiell ist. Danke ~
Lusha Li
3
@LushaLi Das hat mir geholfen: youtube.com/watch?v=9oI7fg-MIpE . Wenn N ein Array ist, in dem jedes Element eine feste Eingabe mit maximaler Größe hat (sagen wir, jedes Element im Array hat nicht mehr als 32 Bit) und Sie einmal eine for-Schleife für dieses Array ausführen, ist dies ein Polynomzeitalgorithmus in der Eingabe Größe N des Arrays. Wenn N jedoch eine ganze Zahl ist und Sie eine Schleife über N ausführen, ist N unbegrenzt und wächst exponentiell in der Anzahl der Bits, die zur Darstellung erforderlich sind. Eine einfache for-Schleife auf N ist also tatsächlich exponentiell. Beachten Sie, dass im Fall des Arrays die Größe jedes Elements im Array nach oben begrenzt war.
max_max_mir
Ich war nicht überzeugt. Es gibt viele Algorithmen mit denselben Eigenschaften, die nicht „pseudo-polynomisch“ sind. Sagen wir, wie komplex ist Sieve of Eratosthenes (oder ein anderer Primzahlenfinder)?
Ofir A.
31

Bei den meisten unserer Probleme haben wir es mit großen Listen von Zahlen zu tun, die bequem in Standard-Int / Float-Datentypen passen. Aufgrund der Art und Weise, wie die meisten Prozessoren dafür ausgelegt sind, 4-8-Byte-Zahlen gleichzeitig ohne zusätzliche Kosten zu verarbeiten (im Verhältnis zu Zahlen, die beispielsweise in 1 Byte passen), kommt es selten zu einer Änderung der Laufzeit durch Skalieren unserer Zahlen oder Innerhalb von Bereichen, auf die wir bei realen Problemen stoßen - der dominierende Faktor bleibt also nur die schiere Menge an Datenpunkten, die n oder m Faktoren, die wir gewohnt sind.

(Sie können sich vorstellen, dass die Big-O-Notation einen konstanten Faktor verbirgt, der 32 oder 64 Bit pro Datum aufteilt und nur die Anzahl der Datenpunkte belässt, wenn jede unserer Zahlen in so viele Bits oder weniger passt )

Versuchen Sie jedoch, mit anderen Algorithmen zu überarbeiten, um auf Datensätze mit großen Ints zu reagieren - Zahlen, für deren Darstellung mehr als 8 Byte erforderlich sind - und sehen Sie, was dies für die Laufzeit bedeutet. Die Größe der beteiligten Zahlen macht auch bei anderen Algorithmen wie der binären Sortierung immer einen Unterschied, wenn Sie über den Sicherheitspuffer hinaus expandieren, den herkömmliche Prozessoren uns "kostenlos" geben, indem sie 4-8-Byte-Stapel verarbeiten.

Der Trick mit dem von uns diskutierten Knapsack-Algorithmus besteht darin, dass er (im Vergleich zu anderen Algorithmen) ungewöhnlich empfindlich auf die Größe eines bestimmten Parameters W reagiert. Wenn Sie W ein Bit hinzufügen, verdoppeln Sie die Laufzeit des Algorithmus. Wir haben diese dramatische Reaktion auf Wertänderungen in anderen Algorithmen vor diesem nicht gesehen, weshalb es so aussieht, als würden wir Knapsack anders behandeln - aber das ist eine echte Analyse dessen, wie es nicht-polynomisch reagiert zu Änderungen in der Eingabegröße.

shaunak1111
quelle
8

Die Laufzeit des Rucksackalgorithmus ist nicht nur an die Größe der Eingabe (n - die Anzahl der Elemente) gebunden, sondern auch an die Größe der Eingabe (W - die Rucksackkapazität) O (nW), die exponentiell ist im Computer binär dargestellt (2 ^ n). Die Rechenkomplexität (dh wie die Verarbeitung innerhalb eines Computers durch Bits erfolgt) betrifft nur die Größe der Eingaben, nicht deren Größen / Werte .

Ignorieren Sie die Wert- / Gewichtsliste für einen Moment. Angenommen, wir haben eine Instanz mit Rucksackkapazität 2. W würde zwei Bits in den Eingabedaten benötigen. Jetzt werden wir die Rucksackkapazität auf 4 erhöhen und den Rest der Eingabe beibehalten. Unsere Eingabe ist nur um ein Bit gewachsen, aber die Rechenkomplexität hat sich verdoppelt. Wenn wir die Kapazität auf 1024 erhöhen, hätten wir nur 10 Bits der Eingabe für W anstelle von 2, aber die Komplexität hat sich um den Faktor 512 erhöht. Die zeitliche Komplexität wächst exponentiell in der Größe von W in binärer (oder dezimaler) Darstellung .

Ein weiteres einfaches Beispiel, das mir geholfen hat, das Pseudo-Polynom-Konzept zu verstehen, ist der naive Primalitätstest-Algorithmus. Für eine gegebene Zahl n prüfen wir, ob sie durch jede ganze Zahl im Bereich 2..√n gleichmäßig geteilt wird, sodass der Algorithmus √ (n - 1) Schritte ausführt. Aber hier ist n die Größe der Eingabe, nicht ihre Größe.

                     Now The regular O(n) case

Im Gegensatz dazu wird die Suche in einem Array nach einem bestimmten Element in Polynomzeit ausgeführt: O (n). Es dauert höchstens n Schritte und hier ist n die Größe der Eingabe (die Länge des Arrays).

[ siehe hier ]

Berechnung der zum Speichern der Dezimalzahl erforderlichen Bits

shaunak1111
quelle
3
Warum betrachten Sie n für Ihr letztes Suchbeispiel nicht auch als binär? Wenn n = 1024, dauert es auch nur 10 Bit. Sollte es also nicht pseudopolynomisch sein?
user1024
7

Ich verstehe das so, dass die Kapazität O (W) gewesen wäre, wenn die Kapazitätseingabe ein Array von [1,2, ..., W] gewesen wäre , das eine Größe von W hat. Die Kapazitätseingabe ist dies jedoch nicht ein Array von Zahlen, es ist stattdessen eine einzelne Ganzzahl. Bei der zeitlichen Komplexität geht es um die Beziehung zur Größe der Eingabe. Die Größe einer Ganzzahl ist NICHT der Wert der Ganzzahl, sondern die Anzahl der Bits, die sie darstellen. Wir konvertieren diese ganze Zahl W später in ein Array [1,2, ..., W] im Algorithmus, was dazu führt, dass die Leute fälschlicherweise denken, W sei die Größe, aber dieses Array ist nicht die Eingabe, sondern die ganze Zahl selbst.

Stellen Sie sich die Eingabe als "ein Array von Dingen" und die Größe als "wie viele Dinge in dem Array" vor. Die Elementeingabe ist tatsächlich ein Array von n Elementen im Array, also Größe = n. Die Kapazitätseingabe ist KEIN Array von W-Zahlen , sondern eine einzelne Ganzzahl , die durch ein Array von Protokollbits (W) dargestellt wird. Erhöhen Sie die Größe um 1 (Hinzufügen von 1 aussagekräftigem Bit). W verdoppelt sich, sodass sich die Laufzeit verdoppelt, daher die exponentielle Zeitkomplexität.

lineil
quelle