Knapsack mit fortlaufender (nicht unterscheidbarer) Bedingung

8

Ich habe Dynamic Programming - Kapsack Problem (YouTube) gesehen. Allerdings löse ich ein etwas anderes Problem, bei dem die Beschränkung das Budget, der Preis, im doppelten, nicht ganzzahligen ist. Ich frage mich, wie kann ich das ändern? Double ist "continuous" ungleich "integer", wo ich 1,2,3 haben kann .... Ich nehme nicht an, dass ich 0,0, 0,1, 0,2 ... tue.

UPDATE 1

Ich dachte über die Umwandlung von double in int durch Multiplikation mit 100. Geld ist nur 2 Dezimalstellen. Aber das bedeutet, dass der Wertebereich sehr groß sein wird?

UPDATE 2

Das Problem, das ich lösen muss, ist:

  

Artikel haben einen Preis (doppelt) & amp; Zufriedenheit (Ganzzahl) Wert. Ich habe ein Budget als Einschränkung und muss den Zufriedenheitswert maximieren.

     

Im Youtube-Video hat der Autor zwei 2d-Arrays wie int [numItems] [possibleCapacity (weight)] erstellt. Hier kann ich nicht als Budget eine doppelte nicht ganze Zahl

    
Jiew Meng 14.01.2012, 07:44
quelle

7 Antworten

15

Wenn Sie Gleitkommazahlen mit beliebiger Genauigkeit verwenden möchten (d. h. keine feste Anzahl von Dezimalstellen haben) und dies keine Brüche sind, funktioniert die dynamische Programmierung nicht.

Die Grundlage der dynamischen Programmierung besteht darin, vorherige Ergebnisse einer Berechnung für bestimmte Eingaben zu speichern. Wenn Sie also Gleitkommazahlen mit beliebiger Genauigkeit verwenden, benötigen Sie praktisch unendlichen Speicher für jede der möglichen Gleitkommazahlen und natürlich unendliche Berechnungen, was unmöglich und nicht optimal ist.

Wenn diese Zahlen jedoch eine feste Genauigkeit haben (wie beim Geld, das nur zwei Dezimalzahlen hat), können Sie diese in ganze Zahlen umwandeln, indem Sie sie multiplizieren (wie Sie bereits erwähnt haben) und dann das Rucksackproblem lösen üblich.

    
Adonais 17.01.2012, 16:22
quelle
5

Sie müssen tun , was Sie in UPDATE 1 gesagt haben: Geben Sie die Budget- und Artikelpreise in Cent aus (vorausgesetzt, wir sprechen über Dollars). Dann sprechen wir nicht von willkürlicher Präzision oder fortlaufenden Zahlen. Jeder Preis (und das Budget) wird eine ganze Zahl sein, es ist nur so, dass diese ganze Zahl Cents darstellt.

Um die Dinge einfacher zu machen, nehmen wir an, das Budget beträgt 10 $. Das Problem ist, dass die Knapsack-Kapazität alle Werte annehmen muss:

%Vor%

Die Werte sind zwei viele. Jede Zeile der SOLUTION MATRIX und der KEEP MATRIX wird 1001 Spalten haben, so dass Sie das Problem nicht von Hand lösen können (wenn das Budget Millionen von Dollars ist, könnte sogar ein Computer es schwer haben) ) aber das ist dem ursprünglichen Problem inhärent (Sie können nichts dagegen tun).

Ihre beste Wette besteht darin, einen vorhandenen Code über KNAPSACK zu verwenden oder Ihren eigenen Code zu schreiben (ich rate dazu nicht).

Wenn Sie keinen vorhandenen Code über KNAPSACK finden und mit Linux / Mac vertraut sind, rate ich Ihnen, das GNU zu installieren Lineare Programmierung Kit (GLPK) und drücken Sie das Problem als Integer Linear Programm oder ein binäres lineares Programm (wenn Sie versuchen, den 0-1 Knapsack zu lösen). Es wird das Problem für Sie lösen (plus Sie können es durch C, C ++, Python und möglicherweise Java verwenden, wenn Sie benötigen). Hilfe zu GLPK finden Sie in diesem tollen Artikel (Sie werden wahrscheinlich Teil 2 , wo es um ganzzahlige Variablen geht. Wenn Sie weitere Hilfe zu GLPK benötigen, hinterlassen Sie bitte einen Kommentar.

BEARBEITEN:

Grundsätzlich versuche ich zu sagen, dass deine Constraint nicht kontinuierlich ist, sie ist diskret (Cent), dein Problem ist, dass das Budget zu viele Cent sein kann, also wirst du es nicht sein in der Lage, es von Hand zu lösen.

Lassen Sie sich nicht einschüchtern, denn Ihr Budget könnte mehrere Dollar betragen - & gt; mehrere hundert Cent. Wenn Ihr Budget nur 18 Cent beträgt, ist die Größe Ihres Problems vergleichbar mit der im YouTube-Video. Der Typ in dem Video würde sein Problem auch nicht (von Hand) lösen können, wenn seine Rucksackgröße 1800 (oder sogar 180) wäre.

    
nitsas 21.01.2012 00:24
quelle
3

Dies ist keine Antwort auf Ihre Frage, sondern könnte auch genau das sein, wonach Sie suchen:

Lineare Programmierung

Ich habe Microsofts Solver Foundation 3 verwendet, um einen einfachen Code zu erstellen das löst das Problem, das Sie beschrieben haben. Es verwendet nicht den Rucksack-Algorithmus , sondern eine Simplex-Methode .

%Vor%

Hier wird das optimale Maximum für die Anzahl der Elemente (Ganzzahlen) mit Preisen (doppelt) mit einer Budgetbeschränkung (doppelt) gefunden.

Aus dem Code ist es offensichtlich, dass Sie einige Artikelmengen in realen Werten haben können (doppelt). Dies wird wahrscheinlich auch schneller als ein Rucksack mit einer großen Reichweite (wenn Sie sich entscheiden, die * 100, die Sie erwähnten) zu verwenden.

Sie können problemlos zusätzliche Einschränkungen angeben (z. B. Anzahl bestimmter Elemente usw.). Der obige Code wurde von dieser MSDN-Anleitung angepasst. wo es zeigt, wie Sie einfach Einschränkungen definieren können.

Bearbeiten

Es ist mir aufgefallen, dass Sie C # nicht verwenden können. In diesem Fall glaube ich, dass es in vielen Sprachen eine Reihe von Bibliotheken für die lineare Programmierung gibt und dass alle relativ einfach zu verwenden sind: Sie geben Beschränkungen und ein Ziel an / p>

Bearbeiten2

Gemäß Ihrem Update 2 habe ich diesen Code aktualisiert, um die Zufriedenheit zu berücksichtigen.

    
neeKo 17.01.2012 17:46
quelle
2

Schauen Sie sich das an. Entschuldigung, ich habe kein Kommentarprivileg.

Bearbeiten 1

Sie sagen, Constraint ist das Budget anstelle von rapsack weight ? Dies bleibt immer noch ein Rucksackproblem.

Oder sagen Sie statt Item Values ​​ als Integers (0-1 Rucksackproblem), haben Sie Brüche . Dann sollte Greedy Ansatz gut gehen.

Bearbeiten 2

Wenn ich Ihr Problem richtig verstehe .. Es heißt

Wir haben n Arten von Elementen, 1 bis n. Jede Art von Artikel i hat einen Wert vi und einen Preis pi . Wir gehen normalerweise davon aus, dass alle Werte und Preise nicht negativ sind. Das Budget ist B .

Die häufigste Formulierung des Problems ist die 0-1 knapsack problem , die die Anzahl xi von Kopien jeder Art von Elementen auf null oder eins beschränkt. Mathematisch kann das 0-1-Rucksack-Problem wie folgt formuliert werden:

%Vor%

Die Antwort von Neo Adonis ist genau richtig. Dynamische Programmierung funktioniert nicht mit beliebiger Genauigkeit in der Praxis.

Aber wenn Sie bereit sind, die Genauigkeit auf 2 Dezimalstellen zu beschränken, dann machen Sie weiter wie in Video erklärt .. Ihr Tisch sollte etwa so aussehen ..

%Vor%

Sie können sogar reelle Zahlen in int umwandeln, wie Sie es erwähnt haben.

Ja, der Bereich der Werte ist sehr groß, und Sie müssen auch verstehen, dass Rucksack ist NP-complete , d. h. es gibt keinen effizienten Algorithmus, um dies zu lösen. nur pseudo polynomial Lösung mit DP. siehe dies und dies .

    
RaviSharma 17.01.2012 14:14
quelle
1

Die Antwort auf Ihre Frage hängt von mehreren Faktoren ab:

  1. Wie groß ist der Wert der Einschränkung (wenn er auf cants skaliert und in Ganzzahlen konvertiert wird).
  2. Wie viele Elemente gibt es?
  3. Welche Art von Rucksackproblem soll gelöst werden?
  4. Welche Genauigkeit wird benötigt?

Wenn Sie einen sehr großen Constraint-Wert (viel mehr als Millionen) und sehr viele Elemente (viel mehr als tausend) haben

Dann ist die einzige Option Gieriger Approximationsalgorithmus . Sortieren Sie die Artikel in absteigender Reihenfolge nach Wert pro Gewichtseinheit und verpacken Sie sie in dieser Reihenfolge.

Wenn Sie einen einfachen Algorithmus verwenden möchten und keine hohe Genauigkeit benötigen

Versuchen Sie erneut, den Greedy-Algorithmus zu verwenden. Der "Zufriedenheitswert" selbst kann eine sehr grobe Annäherung sein, also warum sollte man komplexe Lösungen erfinden, wenn eine einfache Approximation ausreichend ist.

Wenn Sie einen sehr großen (oder sogar kontinuierlichen) Constraint-Wert haben, aber eine ziemlich kleine Anzahl von Elementen (weniger als tausend)

Verwenden Sie dann den Zweig und den gebundenen Ansatz. Sie müssen es nicht von Grund auf neu implementieren. Probieren Sie GNU GLPK . Sein Branch-and-Cut-Solver ist nicht perfekt, aber kann genug sein, um kleine Probleme zu lösen.

Wenn sowohl der Einschränkungswert als auch die Anzahl der Elemente klein sind

Verwenden Sie einen beliebigen Ansatz (DP, Zweig und Grenze oder nur Brute-Force).

Wenn der Constraint-Wert ziemlich klein ist (weniger als Millionen), aber es zu viele (wie Millionen) Elemente gibt

Dann sind DP-Algorithmen möglich.

Der einfachste Fall ist das unbegrenzte Rucksackproblem , wenn es für die Anzahl der Exemplare jeder Art von Artikeln keine Obergrenze gibt. Dieser Wikipedia-Artikel enthält eine gute Beschreibung, wie man das Problem vereinfacht: Dominanzbeziehungen im UKP und wie man es löst: Unbegrenztes Rucksackproblem .

Schwieriger ist das 0-1 Rucksackproblem , wenn Sie jede Art von Gegenständen nur null oder einmal packen können. Und das bounded rapsack problem , das es erlaubt, jede Art von Item bis zu einigen ganzzahligen Grenzzeiten zu packen, ist noch schwieriger. Das Internet bietet viele Implementierungen für diese Probleme, es gibt mehrere Vorschläge im selben Artikel . Aber ich weiß nicht, welcher gut oder schlecht ist.

    
Evgeny Kluev 21.01.2012 19:26
quelle
1

Eine Frage, die ich kürzlich bei sci.op-research gestellt habe, bot mir eine willkommene Abwechslung von einer langweiligen Arbeit, über die ich lieber nicht nachdenke und von der Sie lieber nichts hören würden. Wir wissen, dass die gierige Heuristik das Problem des kontinuierlichen Rucksacks löst maximizec'xs.t.a'x≤bx≤ux∈ℜ + n (1) zur Optimalität. (Der Beweis, Dualitätstheorie verwendend, ist ziemlich einfach.) Nehmen wir an, dass wir hinzufügen, was ich eine Zählungseinschränkung nennen werde, nachgebend maximizec'xs.t.a'x≤be'x = b~x≤ux∈ℜ + n (2) wo e = (1, ..., 1). Kann es durch etwas anderes als die Simplex-Methode, wie eine Variante der Greedy-Heuristik, gelöst werden?

Die Antwort ist ja, obwohl ich mir überhaupt nicht sicher bin, ob das, was ich mir ausgedacht habe, einfacher zu programmieren oder effizienter ist als die Simplex-Methode. Persönlich würde ich eine Verbindung zu einer Bibliothek mit einem linearen Programmierungslöser herstellen und Simplex verwenden, aber es war amüsant, eine Alternative zu finden, auch wenn die Alternative keine Verbesserung gegenüber Simplex darstellt.

Die Methode, die ich vorstellen werde, beruht auf Dualität, insbesondere einem wohlbekannten Ergebnis, dass beide, wenn eine durchführbare Lösung für ein lineares Programm und eine machbare Lösung für ihr duales die komplementäre Schlaffheit erfüllen, in ihren jeweiligen Problemen optimal sind. Ich werde die Doppelvariablen für den Rucksack bezeichnen und die Beschränkungen λ bzw. μ zählen. Beachten Sie, dass λ≥0, aber μ im Vorzeichen uneingeschränkt ist. Im Wesentlichen würde dieselbe Methode, die unten angegeben ist, mit einer Ungleichheitszahlbeschränkung (e'x ≤ b) arbeiten und wäre tatsächlich etwas leichter, da wir a priori das Vorzeichen von & mgr; (nichtnegativ) kennen würden. Das Poster der ursprünglichen Frage hat eine Einschränkung der Gleichheitsanzahl angegeben, also werde ich das verwenden. Es gibt auch Doppelvariablen (ρ≥0) für die oberen Schranken. Das doppelte Problem ist minimumbλ + b~μ + u'ρs.t.λa + μe + ρ≥cλ, ρ≥0. (3)

Da es sich um einen Blogeintrag und keine Dissertation handelt, gehe ich davon aus, dass (2) machbar ist, dass alle Parameter streng positiv sind und dass die optimale Lösung einzigartig und nicht degeneriert ist. Eindeutigkeit und Entartung werden den Algorithmus nicht ungültig machen, aber sie würden die Darstellung komplizieren. In einer optimalen, grundlegenden, machbaren Lösung für (2) gibt es entweder eine oder zwei Basisvariablen - eine, wenn die Knapsackbeschränkung nicht bindend ist, zwei, wenn sie bindend ist - mit jeder anderen variablen Nichtbasis entweder an ihrer unteren oder oberen Grenze. Angenommen, (λ, μ, ρ) ist eine optimale Lösung für das duale von (2). Die reduzierten Kosten für jede Variable xi sind ri = ci-λai-μ. Wenn die Knapsack-Einschränkung nicht bindend ist, dann ist λ = 0 und die optimale Lösung ist xi = uiri & gt; 0b-Σrj & gt; 0ujri = 00ri & lt; 0. (4) Wenn die Knapsack-Einschränkung bindend ist, gibt es zwei Elemente (j, k), deren Variablen grundlegend sind, mit rj = rk = 0. (Indem ich Entartung angenommen habe, habe ich die Möglichkeit, dass die Slack-Variable in der Knapsack-Constraint mit dem Wert 0 grundlegend ist, weggenommen). einstellen xi = uiri & gt; 00ri & lt; 0 (5) und sei b '= b-Σi∉ {j, k} aixi und b~' = b~-Σi∉ {j, k} xi. Die zwei grundlegenden Variablen sind gegeben durch xj = b'-akb~'aj-akxk = b'-ajb''ak-aj. (6)

Der Algorithmus wird in zwei Schritten ablaufen, zuerst nach einer Lösung mit der Rucksack-Bindung suchen (eine grundlegende x-Variable) und dann nach einer Lösung mit der Rucksackbindung suchen (zwei grundlegende x-Variablen). Beachten Sie, dass das erste Mal, wenn wir machbare Primal- und Duallösungen finden, die komplementärer Erschlaffung folgen, beide optimal sein müssen, also sind wir fertig. Man beachte auch, dass wir jedes μ und jedes λ≥0 vervollständigen können, um eine praktikable Lösung für (3) zu erhalten, indem wir ρi = ci-λai-μ + setzen. Wir werden uns also immer mit einer machbaren dualen Lösung befassen, und der Algorithmus wird Primal-Lösungen konstruieren, die die komplementäre Schlaffheit erfüllen. Das Abbruchkriterium reduziert sich daher auf die konstruierte ursprüngliche Lösung, die durchführbar ist.

Für die erste Phase sortieren wir die Variablen so, dass c1≥ ⋯ ≥cn. Da λ = 0 ist und es eine einzige Basisvariable (xh) gibt, deren reduzierte Kosten Null sein müssen, ist offensichtlich μ = ch. Das bedeutet, dass die reduzierten Kosten ri = ci-λai-μ = ci-ch von xi nicht negativ für ih sind. Wenn die durch (3) gegebene Lösung machbar ist - das heißt, wenn Σih. Somit können wir eine Bisektionssuche verwenden, um diese Phase abzuschließen. Wenn wir einen großen Wert von n annehmen, kann die anfängliche Sortierung in O (nlogn) -Zeit erfolgen und der Rest der Phase erfordert O (logn) -Iterationen, von denen jede O (n) -Zeit verwendet.

Leider sehe ich keinen Weg, die Bisektionssuche auf die zweite Phase anzuwenden, in der wir nach Lösungen suchen, bei denen die Rucksackzwangsbindung bindet und λ & gt; 0. Wir werden wieder den Wert von μ suchen, aber diesmal monoton. Zuerst wenden Sie die gierige Heuristik auf Problem (1) an und behalten die Knapsack-Einschränkung bei, ignorieren jedoch die Zählereinschränkung. Wenn die Lösungen zufälligerweise die Zählerbedingung erfüllen, sind wir fertig. In den meisten Fällen wird die Zählbeschränkung jedoch verletzt. Wenn der Zählwert b übersteigt, können wir folgern, dass der optimale Wert von & mgr; in (4) positiv ist; Wenn der Zählwert kleiner als b ~ ist, ist der optimale Wert von μ negativ. Wir starten die zweite Phase mit μ = 0 und bewegen uns in Richtung des optimalen Wertes.

Da die gierige Heuristik Elemente so sortiert, dass c1 / a1 ≥ ∞ ≥cn / an, und da wir mit μ = 0 beginnen, hat unsere aktuelle Sortierreihenfolge (c1-μ) / a1 ≥ ⋯ ≥ (cn-μ )/ein . Wir werden diese Reihenfolge beibehalten (bei Bedarf nachsortieren), wenn wir nach dem optimalen Wert von μ suchen. Um Verwirrung zu vermeiden (ich hoffe), lassen Sie mich annehmen, dass der optimale Wert von μ positiv ist, so dass wir μ im Laufe der Zeit erhöhen werden. Wir suchen nach Werten von (λ, μ), wobei zwei der x Variablen basisch sind, was bedeutet, dass zwei reduzierte Kosten 0 haben. Angenommen, das tritt für xi und xj auf; dann ri = 0 = rj · ci-λai-μ = 0 = cj-λaj-μ (7) ⟹ci-μai = λ = cj-μaj. Es ist leicht zu zeigen (dem Leser als Übung überlassen), dass wenn (c1-μ) / a1 ≥ ⋯ ≥ (cn-μ) / an für den aktuellen Wert von μ, dann der nächsthöhere (niedrigere) Wert von μ was eine Bindung in (7) erzeugt, muss ein fortlaufendes Paar von Items beinhalten (j = i + 1). Darüber hinaus, wieder abdriftend (in diesem Fall bedeutet mehr als zwei Elemente mit reduzierten Kosten 0), wenn wir μ etwas über den Wert, bei dem Elemente i und i + 1 die Kosten 0 reduziert haben, anstoßen, ist die einzige Änderung in der Sortierreihenfolge Die Items I und I + 1 tauschen die Plätze. Keine weitere Bewegung in dieser Richtung wird i und i + 1 veranlassen, wieder zu binden, aber natürlich können beide von ihnen mit ihrem neuen Nachbarn die Straße hinunter gebunden werden.

Die zweite Phase beginnt, beginnend mit μ = 0, wie folgt. Berechne für jedes Paar (i, i + 1) den Wert μi von μ, wobei (ci-μ) / ai = (ci + 1-μ) / ai + 1; Ersetzen Sie diesen Wert durch ∞, wenn er kleiner als der aktuelle Wert von μ ist (dies zeigt an, dass die Verbindung in die falsche Richtung erfolgt). Aktualisiere μ zu miniμi, berechne λ aus (7) und berechne x aus (5) und (6). Wenn x ursprünglich durchführbar ist (was sich auf 0 ≤ xi ≤ui und 0 ≤ xi + 1 ≤ui + 1 reduziert), dann halte an: x ist optimal. Andernfalls tausche ich i und i + 1 in der Sortierreihenfolge aus, setze μi = ∞ (die reindexierten Items i und i + 1 werden nicht wieder gebunden) und berechne μi-1 und μi + 1 neu (kein anderer μj wird durch den Swap beeinflusst).

Wenn die erste Phase kein Optimum gefunden hat (und wenn die gierige Heuristik zu Beginn der zweiten Phase nicht glücklich wurde), muss die zweite Phase mit einem Optimum enden, bevor die Werte von μ nicht mehr ausreichen ( alle μj = ∞). Die Entartung kann entweder mit einem kleinen zusätzlichen Aufwand beim Codieren (zum Beispiel das Prüfen mehrerer Kombinationen von i und j in der zweiten Phase, wenn Dreiwege- oder höhere Bindungen auftreten) oder durch Ausführen kleiner Störungen zum Brechen der Entartung behandelt werden.

    
tamil 24.01.2012 11:07
quelle
1

Die Antworten sind nicht ganz korrekt.

Sie können ein dynamisches Programm implementieren, das das Rucksackproblem mit ganzzahliger Zufriedenheit und beliebigen reellen Zahlen wie Doppeln löst.

Zuerst die Standardlösung des Problems mit ganzzahligen Preisen:

%Vor%

Dies erstellt eine Tabelle, in der die Lösung gefunden werden kann, indem die Rekursion für den Eintrag K [M, n] verfolgt wird.

Jetzt die Lösung für das Problem mit reellem Zahlengewicht:

%Vor%

Die Lösung kann jetzt ähnlich wie die andere Version gefunden werden. Anstatt das Gewicht als erste Dimension zu verwenden, verwenden wir jetzt den Gesamtwert der Elemente, die zum minimalen Gewicht führen. Der Code hat mehr oder weniger dieselbe Laufzeit O (S * N), während der andere O (M * N) hat.

    
Zabuza 15.11.2014 23:37
quelle