0/1 Rucksack-Problembehebung anhand eines dynamischen Programmierbeispiels

โšก Intelligente Zusammenfassung

Das 0/1-Rucksackproblem verwendet dynamische Programmierung, um aus einer Menge gewichteter, bewerteter Pakete so auszuwรคhlen, dass das Gesamtgewicht innerhalb einer Kapazitรคt M bleibt, wรคhrend der Gesamtwert das maximal mรถgliche erreicht.

  • ๐ŸŽ’ Problem: Gegeben seien n Gegenstรคnde mit jeweils dem Gewicht W[i] und dem Wert V[i]. Wรคhle eine Teilmenge, die in die Kapazitรคt M passt und den Gesamtwert maximiert, ohne einen Gegenstand aufzuteilen.
  • ๐Ÿงฎ Wiederauftreten: B[i][j] = max(B[i-1][j], V[i] + B[i-1][j โ€“ W[i]]) erfasst die Entscheidung, ob ein Artikel angenommen oder รผbersprungen wird, fรผr jeden Artikel und jede Kapazitรคt.
  • ๐Ÿงฑ Bottom-Up-Tabelle: Ein (n+1) mal (M+1) Gitter speichert die Teilproblemlรถsungen, sodass bei rekursiven Aufrufen keine Arbeit wiederholt wird.
  • ๐Ÿ” TracE-Back: Das Lesen der Tabelle von B[n][M] bis zur Zeile 0 gibt genau an, welche Pakete die optimale Lรถsung verwendet hat.
  • ๏ธ Komplexitรคt: Die Laufzeit betrรคgt O(nยทM) und der Speicherplatz O(nยทM), wodurch der Algorithmus pseudopolynomiell und ungeeignet ist, wenn M exponentiell ist.
  • ๐Ÿš€ Verwendung: Frachtverladung, Budgetzuweisung, Kryptographie, Ressourcenplanung und KI-gesteuerte Merkmalsauswahl basieren alle auf dem 0/1-Rucksackmodell.

0/1-Rucksackproblem Dynamische Programmierung

Was ist das Rucksackproblem?

Das Rucksackproblem ist ein klassisches kombinatorisches Optimierungsproblem. Ein Supermarkt n Pakete (n โ‰ค 100). Paket i Ein Dieb kann kein Gewicht tragen, das die Kapazitรคt M (M โ‰ค 100) รผbersteigt. Welche Pakete sollte er mitnehmen, um den Gesamtwert zu maximieren?

Eingang:

  • Maximales Gewicht M und die Anzahl der Pakete n.
  • Array aus Gewicht W[i] und entsprechendem Wert V[i].

Ausgang:

  • Maximaler Gesamtwert, der innerhalb der Kapazitรคt erzielt werden kann.
  • Die genaue Zusammenstellung der Pakete, die der Dieb mitnehmen soll.

Der Rucksackalgorithmus lรคsst sich in zwei bekannte Varianten unterteilen:

  • 0/1 Rucksackproblem Gelรถst durch dynamische Programmierung. Jedes Paket wird entweder vollstรคndig mitgenommen oder zurรผckgelassen โ€“ keine Bruchteile und keine Duplikate.
  • Bruchteil-Rucksack-Problem Gelรถst wird das Problem durch eine Greedy-Strategie. Hierbei kann man einen Teil eines beliebigen Pakets nehmen, um die verbleibende Kapazitรคt auszufรผllen.

So lรถsen Sie das Rucksackproblem mithilfe dynamischer Programmierung anhand eines Beispiels

Die Divide-and-Conquer-Methode zerlegt ein groรŸes Problem in Teilprobleme und teilt es so lange weiter, bis jedes Teilproblem einfach zu lรถsen ist. Einfache Rekursion hingegen lรถst oft dasselbe Teilproblem mehrfach und ist somit ineffizient.

Die Kernidee der Rucksack-Dynamischen Programmierung besteht darin, jedes gelรถste Teilproblem in einer Tabelle zu speichern. Wiederholte Aufrufe lesen die Lรถsung aus, anstatt sie neu zu berechnen, wodurch eine exponentielle Rekursion in polynomialen Code umgewandelt wird.

Lรถsen Sie das Rucksackproblem mit dynamischer Programmierung

Lรถsen Sie das Rucksackproblem mit dynamischer Programmierung

Um eine Lรถsung mit dynamischer Programmierung zu entwerfen, befolgen Sie vier Schritte:

  • Lรถse zuerst die kleinsten Teilprobleme.
  • Leiten Sie eine Rekursionsformel her, die aus kleineren Teillรถsungen eine Teillรถsung erzeugt.
  • Die Antworten auf die Teilprobleme werden in einer Tabelle gespeichert, die von unten nach oben mithilfe der Rekursion berechnet wird.
  • Stellen Sie die endgรผltige Antwort anhand der vollstรคndig ausgefรผllten Tabelle zusammen.

Analysieren Sie das 0/1-Rucksackproblem

Der optimale Wert hรคngt von zwei unabhรคngigen Faktoren ab:

  1. Wie viele Pakete werden noch geprรผft?
  2. Das restliche Gewicht, das der Rucksack noch aufnehmen kann.

Da die Zielfunktion von zwei GrรถรŸen abhรคngt, muss die Optionstabelle zweidimensional sein. B[i][j] bezeichnet den Maximalwert bei der Auswahl aus den Paketen {1, โ€ฆ, i} mit Gewichtslimit j.

  • Die endgรผltige Antwort lautet: B[n][M], der beste Gesamtwert รผber alle n Pakete unter Kapazitรคt M.
  • Das insgesamt ausgewรคhlte Gewicht ist stets durch die aktuelle Kapazitรคt begrenzt: B[i][j] โ‰ค j.

Beispiel: Wenn B[4][10] = 8, dann ist das beste Gesamtgewicht der ersten vier Pakete unter Kapazitรคt 10 8. Einige dieser vier Pakete kรถnnen รผbersprungen werden.

Formel zur Berechnung von B[i][j]

  • W[i], V[i] sind Gewicht und Wert des Pakets i, wobei i in {1, โ€ฆ, n} liegt.
  • M ist das maximale Gewicht, das der Rucksack tragen kann.

Basisfall mit einem Paket: fรผr jede Kapazitรคt j โ‰ฅ W[1]:

B[1][j] = W[1]

Entscheiden Sie im allgemeinen Fall, ob Paket i unter Kapazitรคt j aufgenommen werden soll:

  • Wenn Paket i ist รผbersprungen, B[i][j] entspricht dem besten Wert unter Verwendung der Pakete {1, โ€ฆ, i-1} bei Kapazitรคt j:
B[i][j] = B[i - 1][j]
  • Wenn Paket i ist gemacht (nur zulรคssig, wenn W[i] โ‰ค j), B[i][j] gleich V[i] plus dem besten Wert aus den Paketen {1, โ€ฆ, i-1} unter Kapazitรคt j โ€“ W[i]:
B[i][j] = V[i] + B[i - 1][j - W[i]]

Nimm den grรถรŸeren der beiden Kandidaten.

Grundlage der dynamischen Programmierung

Die Kombination der beiden Fรคlle ergibt die vollstรคndige Rekursion:

B[i][j] = max(B[i - 1][j], V[i] + B[i - 1][j - W[i]])

Der Basisfall ist B[0][j] = 0 fรผr jedes j, da Nullpakete unabhรคngig von der Kapazitรคt den Wert Null ergeben.

Berechnen Sie die Optionstabelle

Erstellen Sie B mithilfe der Rekursion. Sobald B gefรผllt ist, steuert dieselbe Tabelle die tracE-Mail, die die ausgewรคhlten Pakete rekonstruiert. Tabelle B hat n + 1 Zeilen und M + 1 Spalten:

  • Zeile 0 ist der Basisfall und ist mit Nullen gefรผllt.
  • Verwenden Sie Zeile 0, um Zeile 1 zu berechnen, Zeile 1, um Zeile 2 zu berechnen, und fahren Sie fort, bis Zeile n vollstรคndig ist.

Berechnen Sie die Optionstabelle

Tabelle der Optionen

Trace

Sobald B abgeschlossen ist, konzentrieren Sie sich auf B[n][M], der optimale Gesamtwert รผber alle n Pakete mit der Kapazitรคt M.

  • If B[n][M] = B[n-1][M]Paket n wurde nicht ausgewรคhlt, also fortfahren tracing von B[n-1][M].
  • If B[n][M] โ‰  B[n-1][M]Paket n wurde ausgewรคhlt, also weiter tracing von B[n-1][M โ€“ W[n]].

Wiederholen Sie den Vorgang, bis Sie Zeile 0 der Tabelle erreicht haben.

Algorithmus zum Nachschlagen der Optionstabelle, um die ausgewรคhlten Pakete zu finden

Hinweis: immer B[i][j] = B[i-1][j], Paket i ist nicht ausgewรคhlt. Der Wert B[n][M] ist der optimale Gesamtwert, der in den Rucksack gepackt wird.

Schritte fรผr tracdie ausgewรคhlten Pakete:

  • Schritt 1: Beginnen wir mit i = n, j = M.
  • Schritt 2: Durchsuchen Sie Spalte j von unten nach oben, bis Sie eine Zeile i finden, in der B[i][j] > B[i-1][j] gilt. Markieren Sie Paket i als ausgewรคhlt: Select[i] = true.
  • Schritt 3: Aktualisiere j = j โ€“ W[i]. Falls j > 0, gehe zurรผck zu Schritt 2, andernfalls zu Schritt 4.
  • Schritt 4: Drucken Sie jedes als ausgewรคhlt markierte Paket aus.

Java Code

Folgende Java Die Methode fรผllt B[][] von unten nach oben, gibt die Tabelle zur รœberprรผfung aus und dann traces die ausgewรคhlten Pakete.

public void knapsackDyProg(int W[], int V[], int M, int n) {
    int B[][] = new int[n + 1][M + 1];

    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= M; j++) {
            B[i][j] = 0;
        }

    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= M; j++) {
            B[i][j] = B[i - 1][j];

            if ((j >= W[i - 1]) && (B[i][j] < B[i - 1][j - W[i - 1]] + V[i - 1])) {
                B[i][j] = B[i - 1][j - W[i - 1]] + V[i - 1];
            }

            System.out.print(B[i][j] + " ");
        }
        System.out.print("\n");
    }

    System.out.println("Max Value:\t" + B[n][M]);
    System.out.println("Selected Packs: ");

    int j = M;
    while (n != 0) {
        if (B[n][j] != B[n - 1][j]) {
            System.out.println("\tPackage " + n + " with W = " + W[n - 1] + " and Value = " + V[n - 1]);
            j = j - W[n - 1];
        }
        n--;
    }
}

Funktion knapsackDyProg() in Java

Funktion knapsackDyProg() in Java

Erklรคrung des Codes:

  1. Tabelle zuweisen B[][] und initialisiere jede Zelle mit 0.
  2. Fรผllen Sie B[][] von unten nach oben mithilfe der Rekursionsformel aus dem vorherigen Abschnitt.
  3. Beginnen Sie jede Zelle mit dem Wert โ€žskip package iโ€œ. B[i-1][j].
  4. Wenn die Auswahl von Paket i mรถglich ist und einen deutlich besseren Wert liefert, รผberschreiben Sie die Zelle.
  5. TracFรผge die ausgewรคhlten Elemente aus Zeile n wieder in Zeile 0 ein.
  6. Wird Paket n ausgewรคhlt, verringert sich die verbleibende Kapazitรคt um W[n-1].

Korrekturhinweis: der ursprรผngliche Codeausschnitt verรคnderte Parameter M wรคhrend ich noch lese B[n][M]Die oben genannte, sicherere Version verwendet einen separaten Cursor. j fรผr die trace.

Das Java Der Treiber fรผhrt den Algorithmus an zwei Beispielen aus:

public void run() {
    // First Example
    // int W[] = new int[]{3, 4, 5, 9, 4};
    // int V[] = new int[]{3, 4, 4, 10, 4};
    // int M = 11;

    // Second Example
    int W[] = new int[]{12, 2, 1, 1, 4};
    int V[] = new int[]{4, 2, 1, 2, 10};
    int M = 15;

    int n = V.length;
    knapsackDyProg(W, V, M, n);
}

Ausgabe fรผr das erste Beispiel:

0 0 0 3 3 3 3 3 3 3 3 3
0 0 0 3 4 4 4 7 7 7 7 7
0 0 0 3 4 4 4 7 7 8 8 8
0 0 0 3 4 4 4 7 7 10 10 10
0 0 0 3 4 4 4 7 8 10 10 11
Max Value:	11
Selected Packs:
	Package 5 with W = 4 and Value = 4
	Package 2 with W = 4 and Value = 4
	Package 1 with W = 3 and Value = 3

Ausgabe fรผr das zweite Beispiel:

0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4
0 0 2 2 2 2 2 2 2 2 2 2 4 4 6 6
0 1 2 3 3 3 3 3 3 3 3 3 4 5 6 7
0 2 3 4 5 5 5 5 5 5 5 5 5 6 7 8
0 2 3 4 10 12 13 14 15 15 15 15 15 15 15 15
Max Value:	15
Selected Packs:
	Package 5 with W = 4 and Value = 10
	Package 4 with W = 1 and Value = 2
	Package 3 with W = 1 and Value = 1
	Package 2 with W = 2 and Value = 2

Zeit- und Speicherkomplexitรคt des 0/1-Rucksackproblems

  • Zeitkomplexitรคt: O(n ยท M) โ€” die beiden verschachtelten Schleifen durchlaufen n Elemente รผber M+1 Kapazitรคtszustรคnde.
  • Raumkomplexitรคt: O(n ยท M) fรผr die vollstรคndige Tabelle, reduzierbar auf O(M) durch Keeping nur die vorherige Zeile, wenn tracEin E-Backup ist nicht erforderlich.

Die Laufzeit ist PseudopolynomPolynomial im Wert von M, aber exponentiell in den Bits, die zur Codierung von M verwendet werden. Deshalb bleibt das 0/1-Rucksackproblem NP-schwer, obwohl dynamische Programmierung in der Praxis effizient ist.

Anwendungen des 0/1-Rucksackproblems

  • Frachtverladung, Containerbeladung und Kommissionierung im Lager unter Einhaltung von Gewichtsbeschrรคnkungen.
  • Budgetaufteilung auf Investitionsprojekte mit fixen Kosten und erwarteter Rendite.
  • Zuschnittprobleme in der Fertigung, bei denen einzelne Teile nicht getrennt werden kรถnnen.
  • Kryptographische Verfahren wie Merkle-Hellman, die auf der Rucksack-Hรคrte basieren.
  • Ressourcenbeschrรคnkte Planung im Cloud Computing und CPU-Task-Platzierung.
  • Merkmalsauswahl beim maschinellen Lernen unter Berรผcksichtigung eines festen Merkmalsbudgets.

Hรคufig gestellte Fragen

Der 0/1-Rucksack wรคhlt eine Teilmenge gewichteter, wertvoller Gegenstรคnde so aus, dass das Gesamtgewicht innerhalb der Kapazitรคt M bleibt, wรคhrend der Gesamtwert maximiert wird. Jeder Gegenstand wird entweder vollstรคndig mitgenommen oder weggelassen.

Das Problem weist รœberschneidungen auf.ping Teilprobleme und optimale Teilstruktur. Die dynamische Programmierung speichert die Antwort auf jedes Teilproblem nur einmal, sodass die Rekursion von exponentieller auf polynomielle Zeit O(n multipliziert mit M) reduziert wird.

Das 0/1-Rucksackproblem erfordert vollstรคndige Gegenstรคnde und wird durch dynamische Programmierung gelรถst. Teilweiser Rucksack ermรถglicht das Aufteilen von Elementen und wird durch einen Greedy-Algorithmus gelรถst, der zuerst das Element mit dem hรถchsten Wert-Gewichts-Verhรคltnis auswรคhlt.

Ja. Das 0/1-Rucksackproblem ist NP-schwer. Dynamische Programmierung benรถtigt O(n ร— M) Zeit, was pseudopolynomiell ist. Die Laufzeit ist polynomiell in M, aber exponentiell in der Anzahl der Bits, die zur Kodierung von M verwendet werden.

Ja. Wenn Sie nur den Maximalwert und nicht die ausgewรคhlten Pakete benรถtigen, behalten Sie einfach die vorherige Zeile der Tabelle. Dadurch reduziert sich der Speicherbedarf von O(n ร— M) auf O(M), wรคhrend die Laufzeit gleich bleibt.

Frachtverladung, Budgetplanung, Materialzuschnitt, Kryptographie, Cloud-Ressourcenplanung und Merkmalsauswahl mittels maschinellen Lernens lassen sich alle auf das 0/1-Rucksackproblem reduzieren. Jedes Packproblem mit fester Kapazitรคt und unteilbaren Gegenstรคnden ist ein Kandidat.

Maschinelles Lernen und Heuristiken des bestรคrkenden Lernens sind der exakten dynamischen Programmierung รผberlegen, wenn M sehr groรŸ ist. Zeigernetzwerke und Graph-Neuronale Netze sagen auรŸerdem Produktauswahlen in sehr groรŸen industriellen Instanzen voraus.

Ja. GitHub Copilot erstellt das Grundgerรผst fรผr die DP-Tabelle, die Rekursion und die tracE-Back in Java, Pythonden C++und generiert Unit-Tests, die sowohl den Maximalwert als auch die ausgewรคhlten Pakete รผberprรผfen.

Fassen Sie diesen Beitrag mit folgenden Worten zusammen: