Letztendlich benötigen Sie einen mathematischen Korrektheitsnachweis. Ich werde im Folgenden auf einige Beweistechniken eingehen, aber bevor ich darauf eingehe, möchte ich Ihnen einige Zeit sparen: Bevor Sie nach einem Beweis suchen, versuchen Sie es mit zufälligen Tests.
Zufällige Tests
Als ersten Schritt empfehle ich Ihnen, Ihren Algorithmus anhand von Zufallstests zu testen. Es ist erstaunlich, wie effektiv dies ist: Meiner Erfahrung nach scheint zufälliges Testen für gierige Algorithmen unangemessen effektiv zu sein. Verbringen Sie 5 Minuten damit, Ihren Algorithmus zu verschlüsseln, und sparen Sie sich möglicherweise ein oder zwei Stunden, um einen Beweis zu finden.
Die Grundidee ist einfach: Implementieren Sie Ihren Algorithmus. Implementieren Sie auch einen Referenzalgorithmus, von dem Sie wissen, dass er korrekt ist (z. B. einen, der alle Möglichkeiten ausgiebig ausprobiert und das Beste ausnutzt). Es ist in Ordnung, wenn Ihr Referenzalgorithmus asymptotisch ineffizient ist, da Sie dies nur auf kleinen Probleminstanzen ausführen. Generieren Sie dann nach dem Zufallsprinzip eine Million kleiner Probleminstanzen, führen Sie beide Algorithmen aus und überprüfen Sie, ob Ihr Kandidatenalgorithmus in jedem Fall die richtige Antwort gibt.
Empirisch werden Sie dies häufig bei zufälligen Tests feststellen, wenn der Algorithmus Ihres Kandidaten für eine Gier inkorrekt ist. Wenn es in allen Testfällen richtig zu sein scheint, sollten Sie mit dem nächsten Schritt fortfahren: der Erstellung eines mathematischen Beweises für die Richtigkeit.
Mathematische Korrektheitsnachweise
OK, wir müssen also beweisen, dass unser gieriger Algorithmus korrekt ist: dass er die optimale Lösung ausgibt (oder, wenn es mehrere optimale Lösungen gibt, die gleich gut sind, dass er eine davon ausgibt).
Das Grundprinzip ist intuitiv:
Prinzip: Wenn Sie nie eine schlechte Wahl treffen, tun Sie alles in Ordnung.
Gierige Algorithmen beinhalten normalerweise eine Folge von Auswahlmöglichkeiten. Die grundlegende Beweisstrategie ist, dass wir versuchen, zu beweisen, dass der Algorithmus niemals eine schlechte Wahl trifft. Gierige Algorithmen können nicht zurückverfolgen - sobald sie eine Entscheidung getroffen haben, sind sie festgeschrieben und werden diese Entscheidung niemals rückgängig machen -, daher ist es wichtig, dass sie niemals eine schlechte Entscheidung treffen.
Was wäre eine gute Wahl? Wenn es eine einzige optimale Lösung gibt, ist es leicht zu erkennen, was eine gute Wahl ist: jede Wahl, die mit der von der optimalen Lösung getroffenen identisch ist. Mit anderen Worten, wir werden versuchen zu beweisen, dass zu jedem Zeitpunkt der Ausführung der Greedy-Algorithmen die bisher vom Algorithmus getroffene Auswahlsequenz genau mit einem Präfix der optimalen Lösung übereinstimmt. Wenn es mehrere gleich gute optimale Lösungen gibt, ist eine gute Wahl eine, die mit mindestens einem der Optima übereinstimmt. Mit anderen Worten, wenn die Auswahlreihenfolge des Algorithmus bisher mit einem Präfix einer der optimalen Lösungen übereinstimmt, ist bis jetzt alles in Ordnung (es ist noch nichts schiefgegangen).
Um das Leben zu vereinfachen und Ablenkungen zu vermeiden, konzentrieren wir uns auf den Fall, dass es keine Bindungen gibt: Es gibt eine einzige, einzigartige optimale Lösung. Alle Maschinen werden auf den Fall übertragen, dass es ohne grundlegende Änderungen mehrere gleich gute Optima geben kann, aber Sie müssen ein bisschen vorsichtiger mit den technischen Details umgehen. Ignorieren Sie zunächst diese Details und konzentrieren Sie sich auf den Fall, in dem die optimale Lösung einzigartig ist. So können Sie sich auf das Wesentliche konzentrieren.
Es gibt ein sehr verbreitetes Beweismuster, das wir verwenden. Wir werden hart arbeiten, um die folgende Eigenschaft des Algorithmus zu beweisen:
Behauptung: Sei die vom Algorithmus ausgegebene Lösung und OSO die optimale Lösung. Wenn unterscheidet sich von ist O , dann können wir optimieren O eine andere Lösung zu erhalten O * , die sich von ist O und streng besser als O .SOOO∗OO
Beachten Sie, warum dies nützlich ist. Wenn die Behauptung wahr ist, folgt, dass der Algorithmus korrekt ist. Dies ist im Grunde ein Beweis durch Widerspruch. Entweder ist dasselbe wie O oder es ist anders. Wenn es anders ist, können wir eine andere Lösung findenSO , die als streng besser OO∗O - aber das ist ein Widerspruch, wie wir definierten die optimale Lösung zu sein , und es kann keine Lösung sein , die als besser. Wir sind gezwungen zu folgern, dass S nicht anders sein kann als O ; S muss immer gleich O seinOSOSODas heißt, der Greedy-Algorithmus gibt immer die richtige Lösung aus. Wenn wir die Behauptung oben beweisen können, haben wir unseren Algorithmus als korrekt erwiesen.
Fein. Wie beweisen wir die Behauptung? Wir denken an eine Lösung als einen Vektor ( S 1 , … , S n ), der der Folge von n Auswahlen entspricht, die vom Algorithmus getroffen wurden, und ebenso denken wir an die optimale Lösung O als einen Vektor ( O 1 , … , O n ) entsprechend der Reihenfolge der Entscheidungen, die zu O führen würden . Wenn S von O verschieden ist , muss ein Index i existieren, bei dem S i ≠ istS( S1, … , Sn)nO( O1, … , On)OSOich ; wir werden uns auf das kleinste konzentrieren, wie ich . Dannwir zwicken O , indem O ein wenig in der i - ten Position Spiel S i ,heißt, werden wir die optimale Lösung optimieren O durch die Änderung i - te Wahl auf die von der GreedyAlgorithmus Auserwählte, und dann Wir werden zeigen, dass dies zu einer noch besseren Lösung führt. Insbesondere definieren wir O ∗ als so etwas wieSich≠ OichichOOichSichOichO∗
O∗= ( O1, O2, … , Oi - 1, Sich, Oi + 1, Oi + 2, … , On) ,
mit der Ausnahme, dass wir den -Teil häufig leicht ändern müssen, um die globale Konsistenz zu gewährleisten. Ein Teil der Beweisstrategie beinhaltet ein gewisses Maß an Klugheit bei der Definition von O ∗ . Dann wird das Fleisch des Beweises darin bestehen, Fakten über den Algorithmus und das Problem zu verwenden, um zu zeigen, dass O ∗ streng besser als O istOi + 1, Oi + 2, … , OnO∗O∗O; Hier benötigen Sie einige problemspezifische Einblicke. Irgendwann müssen Sie sich mit den Details Ihres spezifischen Problems befassen. Dies vermittelt Ihnen jedoch einen Eindruck von der Struktur eines typischen Korrektheitsnachweises für einen gierigen Algorithmus.
Ein einfaches Beispiel: Teilmenge mit maximaler Summe
Dies ist möglicherweise einfacher zu verstehen, wenn Sie ein einfaches Beispiel im Detail durcharbeiten. Betrachten wir das folgende Problem:
Eingabe: Eine Menge von ganzen Zahlen, eine ganze Zahl k Ausgabe: Eine Menge S ⊆ U der Größe k, deren Summe so groß wie möglich istUk
S⊆ Uk
Es gibt einen natürlichen Greedy-Algorithmus für dieses Problem:
- Setze .S: = ∅
- Für :
i:=1,2,…,k
- Sei die größte Zahl in U , die noch nicht ausgewählt wurde (dh ixiUi -größte Zahl in ). HinzufügenU zu S .xiS
Zufällige Tests legen nahe, dass dies immer die optimale Lösung ergibt. Lassen Sie uns also formal beweisen, dass dieser Algorithmus korrekt ist. Beachten Sie, dass die optimale Lösung einzigartig ist, sodass wir uns nicht um Krawatten kümmern müssen. Lassen Sie uns die oben skizzierte Behauptung beweisen:
Behauptung: Sei die von diesem Algorithmus ausgegebene Lösung am Eingang U , k und O die optimale Lösung. Wenn SSU,kO , können wir eine andere Lösung konstruierenS≠Oderen Summe noch größer als O ist .O∗O
Beweis. Angenommen, , und sei i der Index der ersten Iteration, in der x i ∉ O ist . (Ein solcher Index i muss existieren, da wir S ≠ O angenommen haben und nach der Definition des Algorithmus S = { x 1 , … , x k } haben .) Da (nach Annahme) i minimal ist, müssen wir haben x 1 , … , xS≠Oixi∉OiS≠OS={x1,…,xk}iund insbesonderex1,…,xi−1∈O hat die Form O = { x 1 , x 2 , ... , x i - 1 , x ' i , x ' i + 1 , ... , x ' n } , wobei die Zahlen x 1 , ... , x i - 1 , x ' i , ... , x ' nOO={x1,x2,…,xi−1,x′i,x′i+1,…,x′n}x1,…,xi−1,x′i,…,x′nsind in absteigender Reihenfolge aufgeführt. Wenn wir uns ansehen, wie der Algorithmus auswählt , sehen wir, dass wir x i > x ' j für alle j ≥ i haben müssen . Insbesondere gilt x i > x ' i . Definiere also O = O ∪ { x i } ∖ { x ′ i } , dh wir erhalten O ∗, indem wir die i- te Zahl in O löschenx1,…,xixi>x′jj≥ixi>x′iO=O∪{xi}∖{x′i}O∗iOund Hinzufügen von . Nun ist die Summe der Elemente von O ∗ die Summe der Elemente von O plus x i - x ' i und x i - x ' i > 0 , so dass die Summe von O ∗ streng größer als die Summe von O ist . Dies beweist die Behauptung. ◼xiO∗Oxi−x′ixi−x′i>0O∗O■
Die Intuition hier ist, dass, wenn der gierige Algorithmus jemals eine Wahl trifft, die mit inkonsistent ist , wir beweisen können, dass O noch besser sein könnte, wenn es so modifiziert würde, dass es das Element enthält, das zu diesem Zeitpunkt vom gierigen Algorithmus ausgewählt wurde. Da O optimal ist, kann es unmöglich einen Weg geben, es noch besser zu machen (das wäre ein Widerspruch). Die einzige verbleibende Möglichkeit ist, dass unsere Annahme falsch war: Mit anderen Worten, der gierige Algorithmus wird niemals eine Wahl treffen das heißt nicht mit O .OOOO
Dieses Argument wird oft als Austauschargument oder Austauschlemma bezeichnet . Wir fanden den ersten Ort, an dem sich die optimale Lösung von der gierigen Lösung unterscheidet, und stellten uns vor, dieses Element von gegen die entsprechende gierige Wahl auszutauschen (ausgetauschtes x ' iOx′i gegen ). Einige Analysen haben gezeigt, dass dieser Austausch nur die optimale Lösung verbessern kann - aber per Definition kann die optimale Lösung nicht verbessert werden. Die einzige Schlussfolgerung ist also, dass es keinen Ort geben darf, an dem sich die optimale Lösung von der gierigen Lösung unterscheidet. Wenn Sie ein anderes Problem haben, suchen Sie nach Möglichkeiten, dieses Austauschprinzip in Ihrer spezifischen Situation anzuwenden.xi