Dynamische Programmierung in Graphen


In der Dynamik der Unterstützung verarbeiten wir die Tops auf "normale Weise in die Tiefe". Indem wir den Baum in die Tiefen umkreisen, unterstreichen wir die Bedeutung der Dynamik, indem wir die Werte der Unterstützung der Kinder verwenden, die wir bereits im Bypass gezählt haben.

Zum Beispiel werden wir folgendes entscheiden: Dana binäre Baum (mit maximal zwei Kindern an jeder Spitze) mit einem Gewicht (möglicherweise negativ). Wir nennen die Gewichte der Gipfel auf dieser Straße. Das maximale Gewicht des einfachen Pfades in diesem Baum muss gefunden werden.

Zuerst legen wir einen Baum hinter eine Spitze (z.B. oben mit Nummer 1).
Wir werden zwei Arten von Möglichkeiten betrachten:
(1) Vertikale Wege - eines der Enden ist die Vorderkante des zweiten Endes.
(2) Horizontale Wege - keines der Enden der Reise ist ein Vorfahren der zweiten.
Jeder Pfad in einem Baum ist einer dieser Arten.

Jeder horizontale Pfad hat einen höheren Punkt, der am wenigsten verbreitete Ahnen der beiden Enden der Reise. Für die vertikale Fahrt ist der höchste Punkt einfach der Endkrieg.
Um alle möglichen Wege zu betrachten, werden wir die höchsten Punkte des Weges überqueren. Sagen wir, wir haben ein paar Tops. Wenn dies der höchste Punkt eines vertikalen Pfades ist, ist das zweite Ende die Spitze, die irgendwo im Hintergrund einer aufgenommenen Spitze liegt. Wenn dies der höchste Punkt der horizontalen Strecke ist, liegt das erste Ende der Straße in der Unterstützung des linken Kindes, und das andere Ende liegt in der Unterstützung des rechten Kindes (und sonst ist der Gipfel von v nicht wirklich der höchste Punkt). Wir werden es benutzen, um die besten Wege herauszufinden.

Dynamische Programmierung: dp[v] - maximales Gewicht vertikal die Reise mit dem höchsten Punkt in der Spitze von v.
Berechnung dp[v] - Es gibt drei Möglichkeiten, einen optimalen vertikalen Weg mit einem oberen Punkt v zu bauen:
(1) Eine Straße, die nur aus der oberen v besteht. Dann ist das Gewicht nur die Spitze des v. Dies kann als Primärwert der Dynamik verwendet werden.
(2) Nehmen Sie den optimalen vertikalen Weg mit dem höchsten Punkt im linken Kind und erweitern Sie ihn nach oben. Der Wert dieser Route ist dp[left] + w(v).
(3) Nehmen Sie den optimalen vertikalen Weg mit dem höchsten Punkt im rechten Kind und erweitern Sie ihn nach oben. Der Wert dieser Route ist dp[right] + w(v).

Wenn wir das maximale dp[v] nehmen, werden wir das maximale Gewicht der vertikalen Pfade kennen.
Wir müssen die horizontalen Pfade berücksichtigen. Sie können auch von dp betrachtet werden. Durch die Festlegung der Oberseite v als der höchste Punkt der horizontalen Pfade sollte die dp[link] + w(v) + dp[right] einfach als zwei vertikale Pfade von verschiedenen Stützen an der Spitze verbunden werden. Angesichts dieser Werte können wir das maximale Gewicht unter allen Strecken bestimmen.

Es ist alles möglich, dies durch den Umfang des Baumes in die Tiefe zu lösen. Details in Code:
/ Stauraum aus Holz
TreeNode {
int val;
TreeNode* links;
TreeNode* rechts;
TreeNode() : val(0), links(nullptr), rechts(nullptr) {}
TreeNode(int x) : val(x), links(nullptr), rechts(nullptr) {}
TreeNode(int x, TreeNode* links, TreeNode* rechts) : val(x), links(links), rechts(rechts) {}
?

/ globale Antwort - Wert des Maximums
int res;

/ / dp[v] = maximaler Abstandswert
/ mit einem höheren Top v und einem unteren irgendwo in der Spitze von v

/ anstatt dp zu halten
// Lassen Sie uns es einfach als Wert des Vortrags zurückgeben (in die Tiefe)
int calc(TreeNode* v)

/ vert ist der vertikale Weg von oben v, in der Tat der Wert dp[v]
/ Primärwert - Wert in Top v, d.h. nur von oben v
int vert = v-stateval;

/ hor ist ein horizontaler Pfad, mit einem Spitzenpunkt (lca)
/ Initiierter Wert in Top v
int hor = v-stateval;

/ Wenn das linke Kind existiert
wenn (v-nationalleft!= nullptr) {~}
int d = calc(v-nationalleft); // berechnet den dynamischen Wert des linken Kindes
vert = max(vert, d + v-stateval); // Aktualisieren Sie den vertikalen Pfad als Fortsetzung des Pfades des linken Kindes
hor += d; // den linken Zweig der horizontalen Route hinzufügen
♪

/ wenn das richtige Kind existiert
wenn (v-nationalright!= nullptr) {
int d = calc(v-priright); // gezählt die Dynamik des linken Kindes
vert = max(vert, d + v-nationalval); // Aktualisieren Sie den vertikalen Pfad als Fortsetzung des Pfades des rechten Kindes
Hor += d; // Den rechten Zweig der horizontalen Route hinzufügen
♪

/ Erneuern Sie die globale Reaktion durch den vertikalen Weg mit dem höchsten Punkt v
res = max(res, vert);

/ Erneuern Sie die globale Reaktion durch den horizontalen Pfad mit dem höchsten Punkt (lca) in v
res = max(res, hor);

/ Rücksetzen der Peakdynamik v
Rückkehr vert;
♪

int maxPathSum (TreeNode* Wurzel) {
// Initialer Maximalwert gleich Null - leere Straße ohne Spitze
res = 0;

// Beginnen Sie tief
calc(root)

// jetzt relevant
zurück;
♪

Entscheidungen sind durch dynamische Programmierung wichtig bei der Berechnung der Dynamik (die Werte, auf denen die aktuellen Werte vorher berechnet werden sollen).
Wenn also für azyklische Graphen eine dynamische Programmierung erforderlich ist, sollte zunächst die topologische Abstufung der Zeile erstellt werden. Betrachten Sie dann die Dynamik durch die Auswahl der Tops in der Reihenfolge einer aufgebauten topologischen Sortierung (je nach Aufgabe kann die Reihenfolge der Bypass sowohl von der Quelle zur Landebahn als auch umgekehrt sein).

Wenn der Graph Zyklen enthält (keine topologische Sortierung existiert), können zwei Getriebe helfen:

(1) Berechnen Sie die Dynamik n mal die Anzahl der Spitzen in der Reihe (wie im Algorithmus von Ford-Bellman). Aber es erhöht die Asymptoik und funktioniert im Allgemeinen selten effektiv.

(2) Kondensieren der Zählung. Für jede Komponente der starken Verbindung des Referenzrahmens wird die Aufgabe separat gelöst. Die kondensierte Zeile ist azyklisch und kann als Standard-High-Class-Ansatz mit den für die starke Konnektivitätskomponente berechneten Werten als Spitzenwerte verwendet werden. Diese Methode wird hauptsächlich verwendet.