Wie erkennen Sie ein Problem, das für die dynamische Programmierung geeignet ist?


19

Ich habe in letzter Zeit über dynamisches Programmieren nachgelesen. Ich würde gerne von jemandem hören, der von vorne angefangen hat und jetzt ziemlich gut darin ist, DP-Probleme zu identifizieren und zu lösen. Ich bemühe mich, diese Probleme als DP zu identifizieren und eine prägnante Lösung zu finden.

Ich habe die meisten DP - Anfängerprobleme und MIT - Ressourcen usw

Antworten:


17

Ich komme aus der Physik und damit aus der Mathematik. Ich finde es einfach, Probleme zu erkennen, die für rekursive / dynamische Programmierlösungen gut geeignet sind, indem ich Ähnlichkeiten mit Beweis durch Induktion finde .

Im Induktionsnachweis haben Sie zwei Teile:

  • Sie beweisen, dass wenn etwas für die Iteration N zutrifft, dies auch für die Iteration N + 1 zutrifft
  • Sie beweisen, dass dies für Iteration 1 zutrifft

In rekursiver Programmierung / dynamischer Programmierung:

  • Sie identifizieren eine Austrittsbedingung (Sie verdrahten beispielsweise die Lösung für Iteration 1).
  • Sie berechnen die Lösung für die Iteration N unter Angabe der Lösung für die Iteration N-1

Wie andere geantwortet haben, ist es eine Frage der Erfahrung und der Auswahl der Hinweise, aber Sie können andere Fähigkeiten als Leitfaden verwenden. Danach müssen Sie immer die beiden Teile haben, die ich erwähnt habe: Wenn Sie das nicht tun, wird es nicht funktionieren.

So generieren Sie beispielsweise alle Permutationen einer Menge:

  • Ausgangsbedingung: Wenn Sie nur ein Element haben, geben Sie es zurück
  • Rekursion: Die Permutationen einer Menge von N Elementen sind die N Mengen von Permutationen, die Sie erhalten, indem Sie jedes Element auswählen und die mit allen N-1 Mengen von (vielen) Permutationen der Teilmenge kombinieren, die Sie erhalten, indem Sie das Element entfernen.

8

Die meisten dynamischen Programmierprobleme können durch Merken gelöst werden. Das Speichern von Memos ist normalerweise intuitiver und einfacher zu programmieren. Möglicherweise finden Sie es hilfreich, in Bezug auf Memoization anstelle von DP zu denken.

Normalerweise ist es einfacher zu verstehen, ob ein Problem für das Auswendiglernen geeignet ist (die Schritte stimmen mit der Antwort von Slivvz überein , aber ich denke, die mentale Verschiebung ist etwas kürzer). Sobald Sie jedoch ein Problem durch Memo-Erstellung gelöst haben, können Sie überprüfen, wie der Memo-Cache gefüllt wird, und ihn anschließend ohne Rekursion in der richtigen Reihenfolge füllen. Dadurch wird Ihr Algorithmus in einen dynamischen Programmieralgorithmus umgewandelt.

TL; DR; version: Möglicherweise ist es für Sie einfacher, die dynamische Programmierung im Hinblick auf die Speicherung zu verstehen.

Siehe auch StackOverflow: Dynamische Programmierung und Speicherung: Bottom-Up- und Top-Down-Ansätze .


4

Bei der dynamischen Programmierung geht es definitiv um zwei Dinge:

  1. Optimale Unterkonstruktion
    Aus kleineren Lösungen lassen sich größere Lösungen ableiten; Das Lösen ist nicht bidirektional.

  2. Überlappende Teilprobleme
    Die kleinen Lösungen werden viele Male wiederverwendet. Wenn sich die Teilprobleme überhaupt nicht überschneiden, profitieren Sie nicht von DP / Memoization. Was Sie haben, ist stattdessen teilen und erobern .

Der allgemeine Ansatz für DP-Probleme lautet:

  • Schreiben Sie eine naive rekursive oder iterative Version, die funktioniert.

  • Beachten Sie, dass die Funktion redundante Arbeit leistet.

  • Finden Sie einen Weg, um diese überflüssige Arbeit zu vermeiden, oft durch Auswendiglernen.


All dies trifft vom theoretischen Standpunkt aus zu. IMO ist etwas mehr Übung erforderlich, um sich mit der schnellen Identifizierung vertraut zu machen :)
user110036

2

Bis vor einigen Jahren, als ich anfing, Probleme mit Project Euler zu lösen, hatte ich noch keinen einzigen Löser für dynamische Programmierung implementiert - mein Hintergrund ist Mathematik / Physik / numerisches Rechnen, nicht CS . Die DP-lösbaren Probleme gibt es (zB 76 , 158 , 161 , 242Es stellte sich heraus, dass es so ziemlich meine Lieblingssorte ist. Das Erkennen ist definitiv besser, wenn es sich um eine nützliche Technik handelt: Suchen Sie im Grunde nach Dingen, die durch einen rekursiven Divide-and-Conquer-Ansatz gelöst werden könnten, bei dem es auch möglich ist, die Explosion der benötigten Pfade zu zähmen erkundet werden, indem wiederkehrende Teilprobleme erkannt und die zuvor berechneten Ergebnisse wiederverwendet werden; In der Lage zu sein, den minimalen Zustandsvektor zu identifizieren, auf dem man sich einprägen kann - und welcher irrelevante "Verlauf" gelöscht werden kann -, ist der entscheidende Schritt.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.