Muster in der dynamischen Programmierung


Diskleimer: Das nachfolgend beschriebene Verfahren ist nicht universell, kann aber oft die Herausforderung erfüllen oder die richtige Lösung erreichen.

Wenn die Herausforderung besteht, die Masse in nicht erschöpfende Schnitte (Kontraktionssequenzen) optimal zu teilen (oder die Anzahl der geeigneten Crashs zu berechnen), sollte sie durch dynamische Programmierung versucht werden.

Ein Beispiel für eine Lösung ist:
dp[i] - Antwort auf die ersten i Elemente

Berechnung dp[i]: da wir nur die ersten i Elemente betrachten, dann werde ich die letzten sein, was bedeutet, dass dieses Element im letzten Teilabschnitt und am besten dort sein wird. Wir können also die linke Linie der letzten U-Bahn j überqueren. Dabei werden wir den Wert des Unterabschnitts berechnen, und wenn es richtig ist, zählen dp[i] durch dp[j-1] und den Unterabschnitt [j;i].

Wir betrachten die einfache Aufgabe: Es wird eine Masse von ganzen Zahlen gegeben, es muss auf eine Mindestanzahl von nicht erschöpfenden Schnitten gebrochen werden, so dass jede Zahl Teil eines Schnittes ist und dass die gleichen Zahlen in jedem Teilabschnitt liegen. Für einen Satz von 1 2 3 3 2 1 1 muss die optimale Spaltung beispielsweise folgende sein: [1] [2 2] [3 3] [2] [1 1]. Diese Aufgabe wird nicht einfach durch einen einfachen Durchgang durch die Masse gelöst (alle gleichen aufeinander folgenden Elemente werden in einem Unterabschnitt platziert), sondern wir werden sie beispielsweise durch dynamische Programmierung entscheiden.
int n;
cin ventri;

/ Gefüllt mit 1-Anzeige
Vektor (n + 1);
für (in i = 1; i PO = n; i+++)
cin vent arr[i];

/ Anfang +o bei dp
Vektor dp(n + 1000000);

/ Länge Null gebrochen werden, so ist es 0
dp[0] = 0;

/ Betrachten Sie die Antwort auf dp[i] durch Erhöhung i
für (int i = 1; i À= n; i+++) {
/ derzeit arr[i] ist das letzte Element, so wird es die richtigeste Zahl im letzten Sublet sein
// Wir nehmen alle Optionen, wo dieser letzte Schnitt begann.
für (int j = i; j grad 0; j-) {
wenn (arr[j]!= arr[i] {~}
/ Wenn es ein Element gäbe, das nicht gleich dem letzteren war, würden die Schnitte unterschiedliche Zahlen enthalten, was für den Zustand nicht geeignet wäre
// Weiter, um keinen Sinn zu machen, da die linke Linie nach links bewegt wird, fehlt dieses Element nicht, also brechen wir
Bruch
♪

/ eingereicht, dass der letzte Schnitt [j;i]
/ soll die erste j-1 der Zellen optimal teilen und 1 (se cut [j;i]) hinzufügen
dp[i] = min(dp[i], dp[j - 1] + 1];
♪
♪
coutverse vp[n];

Sollten die Elemente keinem der Teilstücke angehören, sollte die entsprechende Option als dp[i] = dp[i - 1] einfach berücksichtigt werden.

Ist es erforderlich, die Masse auf genau k der Cut-offs zu teilen, so wird der zweite Parameter in der dynamischen Programmierung einfach hinzugefügt, wie viele Schnitte.
Ich meine, jetzt zählen wir den folgenden Punkt:
dp[i][j] - Antwort für die ersten i Elemente, wenn wir sie auf genau j der Schnitte brechen.
Halten Sie die Armen im Auge.

Die Änderung ist gleich, aber mit dem zweiten Parameter. Ausgehend von dp[i][k] und über die linke Linie des letzten Teilabschnitts j werden wir dp[i][k] durch dp[j-1][k-1] und den Schnitt [j;i] zählen.

Diskleimer: Das nachfolgend beschriebene Verfahren ist nicht universell, kann aber oft die Herausforderung erfüllen oder die richtige Lösung erreichen.

Wenn auf einer bestimmten Achse (in der Regel die Zeitachse oder die Indizes eines Bereichs) ein Zwischensatz vorhanden ist und einige von ihnen in der besten Weise ausgewählt werden müssen, dass sich die gewählten Schnittpunkte nicht schneiden, dann lohnt es sich, dynamische Programmierung anzuwenden.

Beispiel der Lösung:

Zunächst werden wir die vorhandenen Räume an der rechten Grenze sortieren. Lassen Sie uns die folgende Dynamik setzen: dp[i] - Antwort für die ersten i Intervalle.
Wir werden wie folgt lesen: Zuerst werden wir die Situation betrachten, dass der Raum nicht genutzt wird, dann nur dp[i] = dp[i-1]. Wir weisen darauf hin, dass dadurch sichergestellt wird, dass dp[i] Werte mit dem Wachstum i nicht überschritten werden. Und logisch, indem wir einen neuen Slot hinzufügen, können wir die globale Antwort nicht verschlechtern: entweder ignorieren wir einfach den neuen Slot oder wir können eine bessere Option mit ihm zu gestalten. Wenn wir nun den i-Abstand nutzen wollen, können wir diese Räume nutzen, deren rechte Grenzen kleiner sind als die linke Linie des aktuellen Raumes, weil wir eine Reihe von unerklärlichen Linien wählen müssen. Zu diesem Zweck haben wir ursprünglich die rechten Linienräume sortiert, so dass die notwendige Position nun effektiv erkannt werden kann. Dies kann analytisch, wenn möglich, aber im allgemeinen, ein Binpoisspalt gefunden werden, dessen rechte Grenze geringer ist als die linke Stromlinie und möglichst weit. Maximieren Sie die richtige Linie, wir wollen gierig sein, da die Höhe von i die Antwort nur erhöhen kann. Dementsprechend finden wir die notwendige p und zählen die dp[i] durch dp[p] und i-through.