<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>DP on kenji.blog</title><link>http://kenji.blog/de/tags/dp/</link><description>Recent content in DP on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>de</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 15:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/de/tags/dp/index.xml" rel="self" type="application/rss+xml"/><item><title>【Algorithmus-Illustriert】Dynamische Programmierung (DP) vollständig meistern</title><link>http://kenji.blog/de/p/dp-algorithm-master-guide/</link><pubDate>Sat, 12 Sep 2026 15:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/dp-algorithm-master-guide/</guid><description>&lt;img src="http://kenji.blog/p/dp-algorithm-master-guide/img/eyecatch.jpg" alt="Featured image of post 【Algorithmus-Illustriert】Dynamische Programmierung (DP) vollständig meistern" />&lt;p>Von der Wettbewerbsprogrammierung bis zum praktischen Algorithmus-Design taucht sie in vielen Situationen auf und wird für viele Programmierer zur Hürde: &lt;strong>die Dynamische Programmierung (Dynamic Programming, kurz DP)&lt;/strong>. &amp;ldquo;Ich kann keine Rekursionsgleichung aufstellen&amp;rdquo;, &amp;ldquo;Die Indizes sind fehlerhaft&amp;rdquo;, &amp;ldquo;Ich kann nicht einmal beurteilen, ob es sich um ein Problem handelt, das mit DP gelöst werden kann&amp;rdquo;&amp;hellip; Viele von Ihnen haben wahrscheinlich mit solchen Problemen zu kämpfen.&lt;/p>
&lt;p>In diesem Artikel werden wir alles ausführlich behandeln: vom Wesen der dynamischen Programmierung über konkrete Ansätze (Top-Down und Bottom-Up) bis hin zu praktischen Erklärungen anhand von drei repräsentativen Problemen (Fibonacci-Folge, 0/1-Rucksackproblem und längste gemeinsame Teilfolge). Wir zeigen Implementierungsbeispiele sowohl in C++ als auch in Python und bieten einen Weg zur &amp;ldquo;vollständigen Beherrschung&amp;rdquo; mit Hilfe von mathematischen Formeln und Illustrationen. Es ist ein sehr langer Artikel, aber wenn Sie ihn bis zum Ende gelesen haben, wird Ihre Fähigkeit, Algorithmen zu verstehen, mit Sicherheit einen großen Sprung gemacht haben.&lt;/p>
&lt;hr>
&lt;h2 id="1-was-ist-dynamische-programmierung-dp">1. Was ist Dynamische Programmierung (DP)?
&lt;/h2>&lt;p>Die Dynamische Programmierung (Dynamic Programming) ist eine Entwurfstechnik für Algorithmen, bei der komplexe Probleme in kleinere &amp;ldquo;Teilprobleme&amp;rdquo; zerlegt werden und die Lösungen dieser Teilprobleme gespeichert und wiederverwendet werden, um den Rechenaufwand drastisch zu reduzieren.&lt;/p>
&lt;p>Diese in den 1950er Jahren von Richard Bellman erfundene Methode zeigt bei Optimierungsproblemen eine überwältigende Stärke. Das Wort &amp;ldquo;dynamisch&amp;rdquo; (Dynamic) hat keine besondere Bedeutung; es gibt die Anekdote, dass er damals ein &amp;ldquo;gut klingendes Wort&amp;rdquo; wählte, um Forschungsgelder zu erhalten. Heute hat es jedoch seinen festen Platz als eines der wichtigsten Konzepte in der Informatik eingenommen.&lt;/p>
&lt;p>Damit die Dynamische Programmierung angewendet werden kann, muss das zu lösende Problem die folgenden &lt;strong>zwei wichtigen Eigenschaften&lt;/strong> erfüllen:&lt;/p>
&lt;h3 id="1-1-überlappende-teilprobleme-overlapping-subproblems">1-1. Überlappende Teilprobleme (Overlapping Subproblems)
&lt;/h3>&lt;p>Diese Eigenschaft bedeutet, dass im Prozess der Lösung eines großen Problems &lt;strong>dieselben Teilprobleme immer wieder auftreten&lt;/strong>.&lt;/p>
&lt;p>Zum Beispiel wird bei der später erläuterten Berechnung der Fibonacci-Folge die Berechnung zur &amp;ldquo;Ermittlung des 3. Terms&amp;rdquo; sowohl bei der Ermittlung des 5. als auch des 4. Terms benötigt. Wenn sich Teilprobleme nicht überlappen (z. B. bei Divide-and-Conquer-Verfahren wie Merge Sort), gibt es keinen Vorteil, Lösungen zu speichern, weshalb DP dort nicht anwendbar ist. Gerade weil sie sich überlappen, wird durch das Speichern einmal berechneter Ergebnisse im Speicher (Memoisierung oder Tabellierung) und deren Wiederverwendung eine drastische Geschwindigkeitssteigerung möglich.&lt;/p>
&lt;h3 id="1-2-optimale-teilstruktur-optimal-substructure">1-2. Optimale Teilstruktur (Optimal Substructure)
&lt;/h3>&lt;p>&lt;strong>&amp;ldquo;Die optimale Lösung des Gesamtproblems setzt sich aus den optimalen Lösungen seiner Teilprobleme zusammen.&amp;rdquo;&lt;/strong> Dies ist die Eigenschaft.&lt;/p>
&lt;p>Das Problem des kürzesten Pfades ist ein anschauliches Beispiel. Wenn der kürzeste Weg von Stadt A nach Stadt C über Stadt B führt, muss der &amp;ldquo;Weg von Stadt A nach Stadt B&amp;rdquo; auch der kürzeste Weg von A nach B sein. Wäre der Weg von A nach B nämlich nicht optimal (kürzest), könnte man durch dessen Optimierung auch den Gesamtweg von A nach C weiter verkürzen. Diese Eigenschaft, dass man aus optimalen Teillösungen die optimale Gesamtlösung ableiten kann, bildet die Grundlage für die Zustandsübergänge in der dynamischen Programmierung.&lt;/p>
&lt;hr>
&lt;h2 id="2-zwei-ansätze-top-down-und-bottom-up">2. Zwei Ansätze: Top-Down und Bottom-Up
&lt;/h2>&lt;p>Bei der Implementierung der dynamischen Programmierung gibt es grob zwei Ansätze: &amp;ldquo;Top-Down&amp;rdquo; (Memoisierung + Rekursion) und &amp;ldquo;Bottom-Up&amp;rdquo; (Tabellierung). Die jeweiligen Eigenschaften tiefgreifend zu verstehen und je nach Situation anwenden zu können, ist der erste Schritt zur Meisterschaft.&lt;/p>
&lt;h3 id="top-down-ansatz-memoisierung--memoization">Top-Down-Ansatz (Memoisierung / Memoization)
&lt;/h3>&lt;p>Dies ist ein Ansatz, der bei einem großen Problem ansetzt und rekursiv notwendige Teilprobleme aufruft, um diese zu lösen. Dabei werden die Antworten bereits berechneter Teilprobleme in einem Array oder einer Hashmap &amp;ldquo;notiert (gespeichert)&amp;rdquo;, sodass beim nächsten Mal das Ergebnis aus dem Speicher zurückgegeben wird, ohne die Berechnung erneut durchzuführen.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Vorteile:&lt;/strong>
&lt;ul>
&lt;li>Einfach zu implementieren, da es dem natürlichen Denkprozess (Rekursionsgleichung) folgt.&lt;/li>
&lt;li>Da nur die notwendigen Teilprobleme berechnet werden, ist es vorteilhaft, wenn nur auf einen Teil des gesamten Zustandsraums zugegriffen wird.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Nachteile:&lt;/strong>
&lt;ul>
&lt;li>Es gibt Overhead durch Funktionsaufrufe aufgrund der Rekursion.&lt;/li>
&lt;li>Bei großer Rekursionstiefe besteht das Risiko eines Stack Overflows (besonders bei Sprachen wie Python ist Vorsicht geboten).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="bottom-up-ansatz-tabellierung--tabulation">Bottom-Up-Ansatz (Tabellierung / Tabulation)
&lt;/h3>&lt;p>Dies ist ein Ansatz, der beim kleinsten Teilproblem (Basisfall) beginnt und die Lösungen für sukzessiv größere Probleme mittels Schleifenverarbeitung nacheinander in eine Tabelle (Array) einträgt. Am Ende ist die gesuchte Lösung für das Gesamtproblem an einer bestimmten Stelle der Tabelle gespeichert.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Vorteile:&lt;/strong>
&lt;ul>
&lt;li>Es gibt keinen Rekursions-Overhead, weshalb die Ausführungsgeschwindigkeit hoch ist.&lt;/li>
&lt;li>Der Speicherzugriff ist tendenziell sequentiell, was zu einer guten Cache-Effizienz (Lokalität) führt.&lt;/li>
&lt;li>Die später erläuterte &amp;ldquo;Optimierung der Speicherkomplexität (Wiederverwendung von Arrays)&amp;rdquo; ist einfach durchzuführen.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Nachteile:&lt;/strong>
&lt;ul>
&lt;li>Da alle Zustände berechnet werden, werden im Ergebnis manchmal auch unnötige Zustände berechnet.&lt;/li>
&lt;li>Man muss die Abhängigkeiten der Rekursionsgleichung (topologische Sortierung) genau verstehen und die Schleifen in der richtigen Reihenfolge ausführen.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="3-praxis-teil-1-fibonacci-folge">3. Praxis Teil 1: Fibonacci-Folge
&lt;/h2>&lt;p>Zunächst betrachten wir als grundlegendstes und verständlichstes Beispiel die Fibonacci-Folge.
Die Fibonacci-Folge ist wie folgt definiert:&lt;/p>
$$
F(0) = 0, \quad F(1) = 1 \\
F(n) = F(n-1) + F(n-2) \quad (n \ge 2)
$$&lt;h3 id="3-1-einfache-rekursion-explosion-der-berechnungskomplexität">3-1. Einfache Rekursion (Explosion der Berechnungskomplexität)
&lt;/h3>&lt;p>Was passiert, wenn wir eine rekursive Funktion exakt nach dieser Definition schreiben?&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fib_naive&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">n&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">fib_naive&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">fib_naive&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Diese Implementierung ist intuitiv, führt jedoch zu einer exponentiellen Explosion der Berechnungskomplexität von $O(2^n)$. Das liegt daran, dass die Berechnungen für dieselben Argumente immer wieder wiederholt werden. Unten ist der Rekursionsbaum zur Berechnung von $F(5)$ dargestellt.&lt;/p>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;fib(5)&amp;#34;] --&amp;gt; B[&amp;#34;fib(4)&amp;#34;]
A --&amp;gt; C[&amp;#34;fib(3)&amp;#34;]
B --&amp;gt; D[&amp;#34;fib(3)&amp;#34;]
B --&amp;gt; E[&amp;#34;fib(2)&amp;#34;]
C --&amp;gt; F[&amp;#34;fib(2)&amp;#34;]
C --&amp;gt; G[&amp;#34;fib(1)&amp;#34;]
D --&amp;gt; H[&amp;#34;fib(2)&amp;#34;]
D --&amp;gt; I[&amp;#34;fib(1)&amp;#34;]
E --&amp;gt; J[&amp;#34;fib(1)&amp;#34;]
E --&amp;gt; K[&amp;#34;fib(0)&amp;#34;]
F --&amp;gt; L[&amp;#34;fib(1)&amp;#34;]
F --&amp;gt; M[&amp;#34;fib(0)&amp;#34;]
&lt;/pre>
&lt;p>Wenn wir uns das Diagramm ansehen, können wir erkennen, dass &lt;code>&amp;quot;fib(3)&amp;quot;&lt;/code> und &lt;code>&amp;quot;fib(2)&amp;quot;&lt;/code> mehrmals ausgewertet werden. Genau das ist mit &amp;ldquo;überlappenden Teilproblemen&amp;rdquo; gemeint.&lt;/p>
&lt;h3 id="3-2-top-down-ansatz-memoisierung">3-2. Top-Down-Ansatz (Memoisierung)
&lt;/h3>&lt;p>Wir verwenden ein Array oder ein Dictionary, um einmal berechnete Ergebnisse zu speichern. Dadurch verringert sich die Berechnungskomplexität auf $O(n)$.&lt;/p>
&lt;p>&lt;strong>Python-Implementierung:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fib_memo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">memo&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">None&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">memo&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">memo&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">memo&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">memo&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">n&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Berechnen und in memo speichern&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">memo&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fib_memo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">memo&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">fib_memo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">memo&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">memo&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>C++-Implementierung:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">memo&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="nf">fib_memo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Wenn bereits berechnet, aus Memo zurückgeben
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">memo&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">memo&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Berechnen und im Memo speichern
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">memo&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fib_memo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">fib_memo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">50&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">memo&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">assign&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">fib_memo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-3-bottom-up-ansatz-tabellierung">3-3. Bottom-Up-Ansatz (Tabellierung)
&lt;/h3>&lt;p>Bei diesem Ansatz füllen wir ein Array von den kleinsten Werten aufwärts. Es besteht keine Gefahr eines Stack Overflows, und es läuft extrem schnell.&lt;/p>
&lt;p>&lt;strong>Python-Implementierung:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fib_dp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">n&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>C++-Implementierung:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span> &lt;span class="nf">fib_dp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">long&lt;/span> &lt;span class="kt">long&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-4-optimierung-der-speicherkomplexität">3-4. Optimierung der Speicherkomplexität
&lt;/h3>&lt;p>Wenn wir den Bottom-Up-Ansatz genau betrachten, stellen wir fest, dass zur Berechnung von $dp[i]$ nur die letzten beiden Werte $dp[i-1]$ und $dp[i-2]$ benötigt werden, während frühere Werte nicht mehr gebraucht werden. Daher müssen wir nicht das gesamte Array im Speicher halten, sondern können die Berechnung mit nur zwei Variablen fortsetzen. Auf diese Weise können wir die Speicherkomplexität von $O(n)$ auf $O(1)$ reduzieren.&lt;/p>
&lt;p>&lt;strong>Python-Implementierung:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fib_optimized&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">n&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prev2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prev1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">current&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">prev1&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">prev2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prev2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">prev1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prev1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">current&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">current&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="4-praxis-teil-2-01-rucksackproblem-01-knapsack-problem">4. Praxis Teil 2: 0/1-Rucksackproblem (0/1 Knapsack Problem)
&lt;/h2>&lt;p>Als Nächstes kommt endlich ein echtes Optimierungsproblem. Das 0/1-Rucksackproblem ist als das klassische Einstiegsproblem der dynamischen Programmierung bekannt.&lt;/p>
&lt;h3 id="4-1-problemstellung">4-1. Problemstellung
&lt;/h3>&lt;p>Wir haben einen Rucksack mit der Kapazität $W$. Außerdem gibt es $n$ Gegenstände, und für jeden Gegenstand $i$ ($1 \le i \le n$) sind das Gewicht $weight[i]$ und der Wert $value[i]$ festgelegt.
Wenn wir die Gegenstände so auswählen, dass die Kapazität des Rucksacks nicht überschritten wird, wie groß ist dann der maximale Gesamtwert, den wir erreichen können?
(※ &amp;ldquo;0/1&amp;rdquo; bedeutet, dass es für jeden Gegenstand nur zwei Möglichkeiten gibt: ihn &amp;ldquo;nicht auswählen (0)&amp;rdquo; oder ihn &amp;ldquo;auswählen (1)&amp;rdquo;. Gegenstände können nicht geteilt werden.)&lt;/p>
&lt;h3 id="4-2-zustandsdefinition-und-zustandsübergangsgleichung">4-2. Zustandsdefinition und Zustandsübergangsgleichung
&lt;/h3>&lt;p>Der wichtigste Schritt zur Lösung von DP-Problemen ist die korrekte Definition des &amp;ldquo;Zustands&amp;rdquo; (State).
Bei diesem Problem ändern sich zwei Parameter: &amp;ldquo;Bis zu welchem Gegenstand wir betrachtet haben&amp;rdquo; und &amp;ldquo;Die verbleibende Kapazität des Rucksacks&amp;rdquo;. Daher definieren wir den Zustand wie folgt:&lt;/p>
&lt;p>&lt;strong>Zustandsdefinition:&lt;/strong>
$dp[i][w]$ := Der maximale Gesamtwert, wenn wir nur Gegenstände vom ersten bis zum $i$-ten auswählen, sodass ihr Gesamtgewicht kleiner oder gleich $w$ ist.&lt;/p>
&lt;p>Als Nächstes überlegen wir, wie sich dieser Zustand verändert (Übergang). Wenn wir den $i$-ten Gegenstand betrachten, gibt es zwei Möglichkeiten:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Wenn wir den $i$-ten Gegenstand nicht auswählen:&lt;/strong>
Der maximale Wert entspricht dem maximalen Wert für die ersten $i-1$ Gegenstände bei Kapazität $w$.
Das heißt, $dp[i-1][w]$&lt;/li>
&lt;li>&lt;strong>Wenn wir den $i$-ten Gegenstand auswählen:&lt;/strong>
Da das Gewicht dieses Gegenstands $weight[i]$ ist, benötigt der Rucksack mindestens eine freie Kapazität von $weight[i]$ (also $w \ge weight[i]$). Wenn wir ihn auswählen, erhöht sich der erzielte Wert um $value[i]$, aber die verfügbare Kapazität verringert sich um $weight[i]$. Daher ist es die Summe aus dem maximalen Wert, den wir für die ersten $i-1$ Gegenstände bei der verbleibenden Kapazität $w - weight[i]$ erhalten, und $value[i]$.
Das heißt, $dp[i-1][w - weight[i]] + value[i]$&lt;/li>
&lt;/ol>
&lt;p>Aus diesen beiden Möglichkeiten wählen wir einfach diejenige, die den größeren Wert ($\max$) liefert. Die &lt;strong>Zustandsübergangsgleichung&lt;/strong> sieht also wie folgt aus:&lt;/p>
$$
dp[i][w] =
\begin{cases}
dp[i-1][w] &amp; \text{if } w &lt; weight[i] \\
\max(dp[i-1][w], dp[i-1][w - weight[i]] + value[i]) &amp; \text{if } w \ge weight[i]
\end{cases}
$$$$ dp[0][w] = 0, \quad dp[i][0] = 0 $$&lt;p>Das folgende Mermaid-Diagramm visualisiert das Konzept des Zustandsübergangs.&lt;/p>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;dp[i-1][w] (Gegenstand i überspringen)&amp;#34;] --&amp;gt; C[&amp;#34;Max: dp[i][w]&amp;#34;]
B[&amp;#34;dp[i-1][w - weight[i]] + value[i] (Gegenstand i nehmen)&amp;#34;] --&amp;gt; C
&lt;/pre>
&lt;h3 id="4-3-bottom-up-implementierung-2d-array">4-3. Bottom-Up-Implementierung (2D-Array)
&lt;/h3>&lt;p>Wir setzen diese Formel direkt in Code um.&lt;/p>
&lt;p>&lt;strong>C++-Implementierung:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;algorithm&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">knapsack&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">W&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&amp;amp;&lt;/span> &lt;span class="n">weight&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&amp;amp;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">weight&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2D-Array dp[n+1][W+1] mit 0 initialisieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">W&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Gegenstände einzeln hinzufügen und betrachten
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Alle Kapazitätsmuster berechnen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">w&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">w&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">W&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">w&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">weight&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Bei unzureichender Kapazität nicht auswählbar
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Größeren Wert zwischen Nicht-Auswählen und Auswählen übernehmen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">w&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">weight&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">W&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">W&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">50&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">weight&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">20&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">120&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Max Value: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">knapsack&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">W&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">weight&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;em>(※Hinweis: Da die Array-Indizes in C++ bei 0 beginnen, achten Sie bitte darauf, dass wir hier &lt;code>weight[i-1]&lt;/code> verwenden.)&lt;/em>&lt;/p>
&lt;h3 id="4-4-optimierung-der-speicherkomplexität-1d-array">4-4. Optimierung der Speicherkomplexität (1D-Array)
&lt;/h3>&lt;p>Wir stellen fest, dass bei der Aktualisierung des 2D-Arrays $dp[i][w]$ immer nur auf die vorherige Zeile $dp[i-1]$ zugegriffen wird. Das ist dasselbe Prinzip wie bei der Speicheroptimierung der Fibonacci-Folge.
Daher können wir das Array in ein eindimensionales Array $dp[w]$ komprimieren. Bei der Aktualisierung ist jedoch Vorsicht geboten: Wir müssen die Kapazität $w$ &lt;strong>von groß nach klein (von hinten nach vorne)&lt;/strong> durchlaufen. Wenn wir von vorne aktualisieren, würden wir auf den soeben im selben Schritt aktualisierten &amp;ldquo;$i$-ten Zustand&amp;rdquo; anstelle des &amp;ldquo;$i-1$-ten Zustands&amp;rdquo; zugreifen, was dazu führen würde, dass wir denselben Gegenstand mehrmals auswählen (dies wäre die Lösung für das &amp;ldquo;Rucksackproblem ohne Mengenbegrenzung&amp;rdquo;).&lt;/p>
&lt;p>&lt;strong>Python-Implementierung (Eindimensional):&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">knapsack_1d&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">W&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">weight&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">weight&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">W&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Von W aus rückwärts durchlaufen&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">w&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">W&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">weight&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">max&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">w&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">w&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">weight&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">W&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">W&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">50&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">weight&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">20&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">120&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Max Value:&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">knapsack_1d&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">W&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">weight&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dadurch wird die Speicherkomplexität drastisch von $O(nW)$ auf $O(W)$ verbessert. Dies ist eine unerlässliche Technik in der Praxis und bei der Wettbewerbsprogrammierung.&lt;/p>
&lt;hr>
&lt;h2 id="5-praxis-teil-3-längste-gemeinsame-teilfolge-lcs-longest-common-subsequence">5. Praxis Teil 3: Längste gemeinsame Teilfolge (LCS: Longest Common Subsequence)
&lt;/h2>&lt;p>Als repräsentatives DP-Problem für Zeichenketten betrachten wir die LCS (Longest Common Subsequence). Die LCS ist ein Algorithmus, der in der Praxis weithin Anwendung findet, z.B. bei der Dateidifferenzerkennung (diff-Tools) und der Ähnlichkeitsprüfung von DNA-Sequenzen.&lt;/p>
&lt;h3 id="5-1-problemstellung">5-1. Problemstellung
&lt;/h3>&lt;p>Gegeben seien zwei Zeichenketten $S$ und $T$. Finden Sie die Länge der längsten gemeinsamen Teilfolge (eine Zeichenfolge, die aus der ursprünglichen Zeichenfolge durch Löschen von 0 oder mehr Zeichen gebildet wird, wobei die Reihenfolge erhalten bleibt).&lt;/p>
&lt;p>Beispiel: Wenn $S = \text{"ABCBDAB"}$ und $T = \text{"BDCABA"}$, dann ist die LCS $\text{"BCBA"}$ oder $\text{"BDAB"}$ usw., und ihre Länge beträgt 4.&lt;/p>
&lt;h3 id="5-2-zustandsdefinition-und-zustandsübergangsgleichung">5-2. Zustandsdefinition und Zustandsübergangsgleichung
&lt;/h3>&lt;p>Angenommen, die Längen der Zeichenketten sind $m$ bzw. $n$. Auch in diesem Fall verwenden wir die Längen der Präfixe (Teilzeichenketten vom Anfang) der beiden Zeichenketten als Zustände.&lt;/p>
&lt;p>&lt;strong>Zustandsdefinition:&lt;/strong>
$dp[i][j]$ := Die Länge der längsten gemeinsamen Teilfolge (LCS) zwischen den ersten $i$ Zeichen der Zeichenfolge $S$ und den ersten $j$ Zeichen der Zeichenfolge $T$.&lt;/p>
&lt;p>Wir betrachten den Übergang, indem wir uns auf die letzten Zeichen $S[i-1]$ und $T[j-1]$ konzentrieren.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Wenn $S[i-1] == T[j-1]$:&lt;/strong>
Da die letzten Zeichen übereinstimmen, ist dieses Zeichen definitiv in der LCS enthalten. Daher ist es gleich der LCS des Zustands, bei dem beide Zeichenketten um ein Zeichen verkürzt sind, plus 1.
$dp[i][j] = dp[i-1][j-1] + 1$&lt;/li>
&lt;li>&lt;strong>Wenn $S[i-1] \neq T[j-1]$:&lt;/strong>
Da sich die letzten Zeichen unterscheiden, ist mindestens eines von ihnen nicht in der LCS enthalten. Wir wählen den größeren Wert zwischen dem Fall, dass wir $S$ um ein Zeichen reduzieren ($dp[i-1][j]$), und dem Fall, dass wir $T$ um ein Zeichen reduzieren ($dp[i][j-1]$).
$dp[i][j] = \max(dp[i-1][j], dp[i][j-1])$&lt;/li>
&lt;/ol>
&lt;p>Zusammenfassend ergibt dies die folgende Zustandsübergangsgleichung:&lt;/p>
$$
dp[i][j] =
\begin{cases}
0 &amp; \text{if } i = 0 \text{ or } j = 0 \\
dp[i-1][j-1] + 1 &amp; \text{if } i > 0, j > 0 \text{ and } S[i-1] = T[j-1] \\
\max(dp[i-1][j], dp[i][j-1]) &amp; \text{if } i > 0, j > 0 \text{ and } S[i-1] \neq T[j-1]
\end{cases}
$$&lt;p>Dieser Übergang lässt sich in Mermaid wie folgt darstellen:&lt;/p>
&lt;pre class="mermaid">
graph TD
subgraph &amp;#34;S[i-1] == T[j-1]&amp;#34;
A1[&amp;#34;dp[i-1][j-1]&amp;#34;] --&amp;gt; B1[&amp;#34;+1 --&amp;gt; dp[i][j]&amp;#34;]
end
subgraph &amp;#34;S[i-1] != T[j-1]&amp;#34;
A2[&amp;#34;dp[i-1][j]&amp;#34;] --&amp;gt; C2[&amp;#34;Max --&amp;gt; dp[i][j]&amp;#34;]
B2[&amp;#34;dp[i][j-1]&amp;#34;] --&amp;gt; C2
end
&lt;/pre>
&lt;h3 id="5-3-bottom-up-implementierung">5-3. Bottom-Up-Implementierung
&lt;/h3>&lt;p>Dies kann ebenfalls einfach mit einem 2D-Array implementiert werden.&lt;/p>
&lt;p>&lt;strong>Python-Implementierung:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">longest_common_subsequence&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text1&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">text2&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">int&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text1&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">text2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2D-Array mit m+1 Zeilen und n+1 Spalten, gefüllt mit 0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">_&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">j&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">text1&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">text2&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">max&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">S&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ABCBDAB&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">T&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;BDCABA&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;LCS Length:&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">longest_common_subsequence&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">S&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">T&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>C++-Implementierung:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;algorithm&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">longest_common_subsequence&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">text1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">text2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">text1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">text2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">j&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">j&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">text1&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">text2&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">max&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">j&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">dp&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">S&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;ABCBDAB&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">T&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;BDCABA&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;LCS Length: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">longest_common_subsequence&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">S&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">T&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Auch beim LCS-Problem werden für die Aktualisierung nur die vorherige Zeile (&lt;code>dp[i-1]&lt;/code>) und die aktuelle Zeile (&lt;code>dp[i]&lt;/code>) verwendet, sodass die Berechnung mit einem Array aus zwei Zeilen ($2n$ Elemente) möglich ist. Dies wird als &amp;ldquo;Rolling Array&amp;rdquo; (rollierendes Array) bezeichnet. Es ist eine äußerst nützliche Methode, um die Speicherkomplexität drastisch zu verringern.&lt;/p>
&lt;hr>
&lt;h2 id="6-denkprozess-zur-beherrschung-der-dynamischen-programmierung">6. Denkprozess zur Beherrschung der Dynamischen Programmierung
&lt;/h2>&lt;p>Bisher haben wir uns verschiedene Probleme angesehen, aber wie sollten Sie vorgehen, wenn Sie mit einem unbekannten DP-Problem konfrontiert werden? Behalten Sie immer die folgenden Schritte im Hinterkopf:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Kann dieses Problem mit DP gelöst werden? (Überprüfung der Bedingungen)&lt;/strong>
Tritt derselbe Zustand mehrfach auf, wenn wir rekursiv denken (Überlappende Teilprobleme)? Können wir durch Kombination der besten Entscheidungen zum Gesamtoplimum gelangen (Optimale Teilstruktur)?&lt;/li>
&lt;li>&lt;strong>Den Zustand (State) definieren&lt;/strong>
Identifizieren Sie Variablen, die darstellen: &amp;ldquo;Wo bin ich jetzt?&amp;rdquo;, &amp;ldquo;Was ist übrig?&amp;rdquo;, &amp;ldquo;Was sind die bisherigen Einschränkungen?&amp;rdquo;. Die klare Formulierung der Bedeutung von Indizes ist der beste Schutz gegen Bugs.&lt;/li>
&lt;li>&lt;strong>Die Zustandsübergangsgleichung (Transition) überlegen&lt;/strong>
Wie bewege ich mich von einem Zustand zum nächsten? Was sind die Optionen? Nehme ich das Maximum (oder Minimum) davon, oder summiere ich sie? Dies ist das Herzstück des Algorithmus.&lt;/li>
&lt;li>&lt;strong>Die Anfangsbedingungen (Base Case) festlegen&lt;/strong>
Legen Sie die Initialwerte des Arrays oder den Startpunkt der Berechnung fest. Behandeln Sie Edge Cases korrekt, bei denen eine triviale Antwort existiert, wie z.B. 0 Gegenstände oder ein String der Länge 0.&lt;/li>
&lt;li>&lt;strong>Die Reihenfolge der Berechnung (Topological Order) überprüfen&lt;/strong>
Bei der Bottom-Up-Implementierung müssen alle Quellzustände des Übergangs bereits berechnet sein, bevor der Zielzustand berechnet werden kann. Achten Sie genau auf die Richtung der Schleifen.&lt;/li>
&lt;/ol>
&lt;h2 id="7-zusammenfassung">7. Zusammenfassung
&lt;/h2>&lt;p>In diesem Artikel haben wir detailliert erklärt, von den grundlegenden Theorien der dynamischen Programmierung über konkrete Implementierungsansätze bis hin zu repräsentativen Optimierungsproblemen.&lt;/p>
&lt;ul>
&lt;li>Dynamische Programmierung ist eine Methode, die rekursive Beziehungen nutzt, um Lösungen von Teilproblemen wiederzuverwenden.&lt;/li>
&lt;li>Der &lt;strong>Top-Down-Ansatz (Memoisierung)&lt;/strong> ist intuitiv zu implementieren, während der &lt;strong>Bottom-Up-Ansatz (Tabellierung)&lt;/strong> durch einen geringeren konstanten Faktor besticht und sich leichter speicheroptimieren lässt.&lt;/li>
&lt;li>Wenn die mathematische Formel (Zustandsübergangsgleichung) korrekt aufgestellt ist, wird die Implementierung sehr einfach.&lt;/li>
&lt;li>Techniken zur Reduzierung der Speicherkomplexität (wie die Eindimensionalisierung von Arrays oder Rolling Arrays) sind unerlässlich, wenn auf praktischer Ebene hohe Leistung gefordert ist.&lt;/li>
&lt;/ul>
&lt;p>Die dynamische Programmierung kann anfangs schwer verständlich erscheinen. Durch wiederholtes Training, &amp;ldquo;Zustandsdefinitionen&amp;rdquo; und &amp;ldquo;Übergänge&amp;rdquo; in verschiedenen Problemen zu finden, werden Sie jedoch allmählich Muster erkennen. Es gibt noch fortgeschrittenere Anwendungen wie Tree-DP, Digit-DP, Bitmask-DP oder Interval-DP, aber sie alle bauen auf dem Fundament der hier gelernten &amp;ldquo;überlappenden Teilprobleme&amp;rdquo; und der &amp;ldquo;Optimierung&amp;rdquo; auf.&lt;/p>
&lt;p>Beeilen Sie sich nicht, sondern vertiefen Sie Ihr Verständnis, indem Sie mit Papier und Stift DP-Tabellen tatsächlich aufzeichnen. Wenn Sie in der Lage sind, die wahre Kraft von Algorithmen zu entfesseln, wird sich die Welt des Programmierens für Sie noch weiter öffnen.&lt;/p></description></item></channel></rss>