So, guten Morgen. Wir sind dabei,
die Grundlagen zur Berechnung kürzester Fade zu wiederholen.
Damit habe ich letzte Vorlesungen angefangen. So ein bisschen Zeitraffer-mäßig,
dass man normalerweise so im dritten Semester über dieses Thema schon lernt.
Und das machen wir jetzt noch ein bisschen. Und danach werden wir
uns mit der Fragestellung der Berechnung kürzester Fahrlässischen allen Knoten berechnen, beschäftigen.
Und das haben wir letztes Mal schon gesehen. Das erste,
was man, so kennenlernt,
wenn es um kürzeste Pfade geht, ist die Breitensuche,
die Breitensuche löst das kürzeste Pfadeproblem in Graphen mit Uniformen, Kantengewichten.
Das heißt, alle Kanten sind gleich lang. Da kann man die verwenden,
die Breitensuche verwendet einfach nur eine Warteschlange,
in der sie quasi die Knoten,
die quasi die Suchfrontbilden speichern und dann nach und nach bearbeitet
und dann auf die Art und Weise die kürzesten Pfade berechnet.
Das ist noch ein Beispiel, in dem man das sehen konnte.
Das haben wir uns schon angeschaut. Dann Laufzeit,
Breitensuche ist Linearzeit, das heißt O von V plus
Ähm, das wollen wir alle mal beschauen. Guck mal,
gerade ob ich noch Batterien habe. Ähm, so,
und ähm, als nächstes, ähm, äh,
schaut man sich natürlich die Probleme an, wo wir konkrete Kantengewichte haben.
Und, äh, da, ähm,
betrachtet man zunächst einmal die Struktur des Problems.
Wir haben dann gesehen, ähm, dass, ähm,
ökürseste Pfade, die das Kriterium der optimalen Teilstruktur erfüllen.
Das heißt, wenn sie einen kürzesten Pfad haben,
der irgendwo von V1 zu VK führt, äh,
dann ist jeder Teilfahrt entlang dieses Pfades ebenfalls ein kürzester Part.
Denn wenn es hier einen kürzeren Pfad zwischen zwei Knoten,
I und J gäbe,
zum Beispiel diesem Pfad PIJ-Strich,
dann wäre natürlich auch der Pfad von V1
noch Frau
Kürzer, wenn wir diesen kürzeren Teilfahrt-PEJ-Strich verwenden. Diese Eigenschaft
der optimalen Teilstruktur ist ganz zentral und verwenden wir immer wieder implizit bei der Berechnung kürzester Pfade.
Ja, dann haben wir uns angeschaut, was passiert bei negativen Kantengewichten. Hier müssen wir aufpassen,
weil insbesondere der Diikser-Algorithmus nicht funktioniert bei negativen Kantengewichten, insbesondere passieren unangenehme Dinge,
wenn wir Zyklen haben und diese Zyklen in der Summe einen Zyklus mit negativer Gesamtlänge beschreiben,
wie zum Beispiel hier, wir dann durch wiederholtes,
durchlaufendes Zyklus, die Entfernung immer weiter reduzieren können.
Und in diesem Fall erhalten diese Knoten dann eine Entfernung von minus unendlich.
Dann haben wir gesehen, dass zur Repräsentierung kürzester Pfade wir Baumstrukturen verwenden können.
Das resultiert einfach aus der Tatsache der optimalen Teilstruktur. Das bedeutet,
ausgehend von einem Startpunkt S, der dann auch die Wurzel dieses Baumes charakterisiert,
können wir alle kürzesten Pfade beschreiben,
indem wir von S aus jeweils die Pfade zu den Knoten beschreiben,
weil für weiter entfernte Knoten jede Teilfahrt wiederum optimal ist,
erhalten wir so einen Baum.
Es können keine Zyklen entstehen, es können auch keine Verzweigung,
irgendeine Art entstehen. Ja, jede Teilentfernung oder jeder Knoten
auf dem Pfad wird durch den kürzesten Pfad beschrieben und dann entsteht diese Baumstruktur.
Wichtig ist allerdings, immer daran zu denken,
dass weder der kürzeste Pfad noch dieser Baum der kürzesten Pfade eindeutig ist.
Also es kann durchaus sein, dass es unterschiedliche Pfade gibt,
die alle die gleiche Länge haben und hier wird in einem kürzesten Pfadebaum immer nur ein Repräsentant wiedergegeben,
der ist im Zweifelsfall dann wild wie möglich,
wie in diesem Beispiel, da können Sie von S über T zu X gelangen.
Das sind mit neuen Einheiten, hier drei über die erste
Kante und sechs über die zweite.
Sie können aber auch dem Pfad über Tee und Y
wählen und dann haben Sie ebenfalls neun Einheiten,
um dahin zu kommen und sind einfach zwei alternative Pfade.
Im kürzesten Pfadebaum wäre dann einfach nur einer dieser beiden Varianten repräsentiert.
Ja, der zentrale Schritt, in fast allen kürzesten Wege Algorithmen ist die sogenannte Relaxation.
Das heißt, man schaut sich eine Kante an
Und bei dieser Kante prüft man, ob wir einen Pfad verkürzen können,
indem wir die Kante verwenden.
Und wenn ja, dann verkürzen wir eine Schranke,
die wir haben für die Länge des kürzesten Pfades und merken uns den entsprechenden Vorgängern.
Das ist die Redaktionsoperation, die heißt die Relax,
steht unten auf der Folie und die kriegt als Parameter zwei Knoten,
U&V und diese Gewichtsmatrix W,
wo wir also die Kantenlängen aller Kanten gespeichert haben.
Und dann prüfen wir halt, ob die Distanz,
die wir bisher berechnet haben für den Knoten V,
größer ist,
als die Distanz zu Knoten
Plus die Kantenlänge von UNAV. Und wenn das der Fall ist,
dann haben wir einen kürzeren Pfad zur Knoten-V gefunden,
der nämlich über U führt.
Wir aktualisieren dann in der nächsten Zeile diese Distanz.
Und wir merken uns in dem Ray P,
jeweils den Vorgänger und wissen damit, wie der Pfad verläuft.
Also P gibt quasi den kürzesten Wege warm an.
Die Berechnung kürzester Pfade erfolgt dann also mit dieser Relaxationsoperation,
mit einer einfachen Strategie. Wir beginnen damit,
dass am Anfang alle Entfernungen oder alle Schranken für die Entfernung,
das sind diese D-Werte,
auch unendlich gesetzt werden
Und wir nähern uns dann durch ein sukzessives Verkleinern,
dieser Schranke, den tatsächlichen Längen der kürzesten Pfade an.
Dieses sukzessive Anpassen erfolgt so, dass wir immer dann eine Anpassung vornehmen,
wenn wir tatsächlich einen kürzeren Pfad gefunden haben.
Und das machen wir immer durch diese Relax-Operation.
Also die kürzesten Pfadalgorithmen haben also immer eine Initialisierungsfunktion.
Da werden diese D-Werte alle auf unendlich gesetzt.
Die Vorgänge werdeten Vorgänger werden alle auf Nil gesetzt und
nur der D-Wert für den Startknoten wird auf null gesetzt.
Wir wissen, dass wir den quasi natürlich mit der Entfernung null erreichen können,
weil wir keinen Weg durchlaufen müssen, um dahin zu kommen.
Und dann werden wir diese Relaxationsoperation anwenden in einer geschickten Art und Weise,
um so quasi die kürzesten Pfade zu berechnen.
Es gibt eine Reihe von Eigenschaften,
die kürzeste Pfade erfüllen und insbesondere auch diese Relaxationsoperation erfüllt.
Und darauf fußt quasi die Korrektheit aller kürzesten Pfadealgorithmen,
die wir so haben, auf diesen Eigenschaften.
Sie finden im Kormen auch einen vollständigen Beweis aller dieser Eigenschaften.
Das werde ich hier in der Vorlesung nicht machen.
Das können Sie sich mal durch durchlesen, wenn sie möchten.
All diese Eigenschaften sind im Prinzip leicht nachvollziehbar.
Also sie beschreiben das, was wir eigentlich auch erwarten,
wie ein Algorithmus auf der Basis der Relaxation sich verhält.
Das Einzige, was vielleicht ein bisschen schwieriger ist, ist diese Konvergenzeigenschaft.
Wir können ja nochmal schnell durchgehen. Also das Erste,
was natürlich gilt, für kürzeste Pfade ist die Dreiecksumgleichung.
Das heißt, für jede Kante UV,
die es in dem Grafen gibt, muss der kürzeste,
die Länge des kürzesten Pfades von S nach V,
kleiner oder gleich der Länge des kürzesten Pfades von S nach U sein,
plus die Kantenlänge, um von UNAV zu gelangen.
Weil wenn der eben nicht so wäre, dann hätten wir einen Widerspruch,
weil dann der kürzeste Pfad von S nach Uplus,
die Verwendung dieser Kante zu einem kürzeren Pfad führen würde,
als der, der die Grundlage für dieses Delta-SV war.
Also die Dreiecksumgleichung ist immer erfüllt. Die Pfadrelaxationseigenschaft besagt nun,
das ist quasi ein Teil der Korrektheitsbeweise zur für kürzte Wege-Algorithmen,
der die besagt, dass wenn wir einen Pfad haben mit Knoten V0,
V1 bis VK, Und das sei jetzt ein kürzester Pfad von SCV.
Dann gilt, wenn wir alle kannten,
entlang dieses Pfades in genau dieser Reihenfolge relaxieren, dann gilt nachher,
dass unsere Schranke D von V der Länge des kürzesten Pfades entspricht.
So, kann man sich das vorstellen, dass das korrekt ist?
Ja, also sie können sich wahrscheinlich auch sofort vorstellen,
wie man das beweist. Da macht man halt einen Induktionsbeweis über
die Länge dieses Pfades. Und intuitiv kann man sagen,
naja, wenn für S wissen wir,
dass wir die Länge korrekt bestimmt haben,
die Lenke des kürzesten Pfades
Und für den Knoten V.1 wissen wir, dass wir das getan haben,
nachdem wir die Kante von V.0 nach V.1 relaxiert haben.
Und dementsprechend können wir dann den nächsten Schritt zeigen,
wenn wir dann im Anschluss die Kante von V.1 nach V.2 relaxieren,
haben wir dann den kürzesten Fahrt für den Knoten V.2 bestimmt.
Und wenn wir alle Kanten relaxieren, dann haben wir am
Ende die kürzesten Pfaddistanz für den letzten Knoten korrekt bestimmt.
Also das ist der Trick, aber wir müssen dafür sorgen,
dass wir alle kannten in der Reihenfolge,
in der sie den kürzesten Faden vorkommen, relaxieren müssen.
Und dann haben wir automatisch wie ein korrektes, kürzeste Pfade-Verfahren entwickelt.
Okay, hier nochmal Eigenschaften, diese Algorithmen, die erste Eigenschaft ist die Eigenschaft der oberen Schranke. Das bedeutet,
dass für die kürzten Pfadalgorithmen immer gelten wird,
das D von V, also die Schranke,
die wir berechnen, eine obere Schranke ist,
das heißt D von V ist immer größer,
gleich Delta-SV und diese Schranke fällt monoton, ja,
sie wird nie wieder größer, das ist auch leicht nachvollziehbar,
dass es in den Algorithmen so ist,
weil das D von V immer die Distanz eines Real existierten untersuchten Pfades schon widerspiegelt.
Ja, und wenn das, das muss natürlich monoton fallen,
weil wenn ich in der längeren Fahrt mal sehe,
dann werde ich das in D von V natürlich nicht speichern.
Zweite Eigenschaft ist, die kein Pfad oder ein No-Path-Property,
kein Pfadeigenschaft. Das heißt, wenn es überhaupt keinen Pfad
gibt von SCV, dann bleibt der D-Wert unendlich.
Er wird sich also dann nicht verringern. Daran können wir immer erkennen,
welche Knoten erreichbar sind und welche nicht erreichbar ist.
Dann die Konvergenzeigenschaft, die Konvergenzeigenschaft besagt, dass wenn U
Vorgänger von V auf einem kürzesten Pfad von S zu V ist.
Ja, ist also der Knoten, der davor liegt. Dann können wir sagen,
dass wenn die kürzeste Pfaddistanz von DU korrekt berechnet ist,
also wenn DU gleich Delta SU ist, also wir wissen,
dass wir für den Knoten U die kürzeste Pfadlänge korrekt berechnet haben,
wenn das zu irgendeinem Zeitpunkt vor der Relaxation der Kante von UNAV gilt und wir führen dann diese Relaxation durch,
dann gilt zu jedem Zeitpunkt nach der Relaxation,
dass für den Knoten V ebenfalls der kürzeste Pfad berechnet wurde
Das ist eine ganz wichtige Eigenschaft, weil die besagt,
dass wir nur dafür sorgen müssen,
dass die Relaxationsoperationen irgendwann einmal in der richtigen Reihenfolge stattgefunden haben müssen.
Dazwischen können auch beliebige andere Dinge passieren, aber irgendwann müssen sie
einmal stattgefunden haben in der korrekten Reihenfolge, gemäß des kürzesten Pfades.
Und dann wissen wir, dass wir den kürzesten Pfad korrekt berechnet haben.
So, dann, ja,
die Speicherung des kürzesten Pfades über diese P,
wie so dieses P-Array, das ist der Vorgängerteil Graf,
das ist die Vorgängerteilgraf Eigenschaft oder Short
des Partes
Three Property. Wenn also für den Knoten V gilt,
dass der kürzeste Pfad in der Länge korrekt berechnet wurde,
dann beschreibt gerade dieses Pi, das ist ja der Vorgänger Teilgraf,
einen Baum, kürzester Pfade mit Wurzel S.
Also wir erkennen dann, wir sehen dann in dem Pi-Wert
für den Knoten V genau den Vorgänger bei uns.
Okay, das sind die wichtigen Eigenschaften,
die die kürzesten Pfadalgorithmen haben und man kann die an verschiedenen
Algorithmen immer wieder sehen,
dass die eintreten
So, der erste Algorithmus, den man sich so anschaut,
der eigentlich direkt dieses Konzept,
was wir hier gesehen haben, der Pfadrelaxationseigenschaft umsetzt,
indem man einfach sagt, naja, es reicht ja,
wenn wir einfach nur die Kanten in allen möglichen Reihenfolgen relaxieren,
weil dann wissen wir,
dass der kürzeste Pfad hat irgendeine spezielle Reihenfolge von den Kanten und wenn wir alle Reihenfolgen,
die möglich sind, relaxieren,
dann haben wir den kürzesten Pfad auch relaxiert und dann haben wir die kürzeste Pfadlänge korrekt berechnet.
Das hört sich jetzt ganz grausam an, weil man dann sagt,
naja, da gibt es ja wahrscheinlich irgendwie exponentiell viele Möglichkeiten, diesen Kanten anzuordnen.
Das ist schon richtig. Und jetzt kommt genau diese Konvergenzeigenschaft,
dass wir sagen, wir müssen nicht sozusagen alle Pfade betrachten,
sondern es reicht, sicherzustellen,
dass in einer Sequenz von Relaxationsoperationen wir quasi den kürzesten Pfad irgendwie wiederfinden können,
dass die Kanten entlang des kürzesten Pfades in dieser Reihenfolge in dieser Sequenz vorkommen.
Und das Einzige, was wir dann tun müssen,
ist, dass wir sagen, naja, okay,
es gibt dann gewisse Anzahl von Kanten.
Ja, das sind Betrag von E., viele Kanten.
Hier, jede Kante beschreibt quasi ein Stück Pfad von irgendeinem Knoten U zu irgendeinem Knoten
V. Und das sind Betrag von E.V. Jetzt können wir überlegen,
wie lang ist denn so ein kürzester Pfad bezüglich der Anzahl der Kanten maximal.
Und dann wissen wir, das können natürlich höchstens Betrag von
V minus 1 viele Kanten sein. Ja,
weil wenn das noch mehr Kanten wären,
dann hätten wir ja einen Zyklus gebaut, ja,
weil dann würde ja entlang dieses Pfades würden ja mehr als V-Knoten vorkommen.
Und dann hätten wir irgendwie einen Zyklus und den kann man natürlich weglassen.
Der kann gar nicht notwendig sein, um einen kürzesten Pfad zu beschreiben.
Es sei denn, er hat negative Länge. Da müssen
wir natürlich aufpassen. Dann würde das sein Problem führen. Okay,
das Einzige, was wir also machen müssen, ist,
wir durchlaufen diese Kanten einmal und das machen wir jetzt nicht einmal, sondern das machen wir ganz häufig.
Wir nehmen immer wieder alle Kanten hier, ja,
und wenn wir das Ganze hier genau V minus eins mal machen,
dann können sie sich jeden beliebigen Pfad raussuchen,
Und die Kanten entlang des Pfades können sie sich hier aus
den einzelnen Zeilen herauspicken und haben den dann in jeder beliebigen Reihenfolge der Kanten,
können sie den hier rekonstruieren.
Sie können jeden Pfad nehmen und der Pfad beginnt dann vielleicht
mit dieser Kante und dann verwendet der Pfad diese Kante und
dann verwendet er diese Kante und so weiter.
Und irgendwann ist er in seinem Zielknoten angelangt und dann sehen sie,
dass sie entlang der, dass sie entlang des kürzesten Pfades,
die Kanten einmal relaxiert haben, dann haben sie den kürzesten Pfad berechnet.
Das ist die Idee des Bellmann-Fortalgorithmus und die
wird ganz so umgesetzt. Die Kanten werden also in allen
möglichen Reihenfolgen relaxiert
Wir initialisieren hier, ja. Dann kommt diese Vorschleife,
die Vorschleife, das ist das,
was ich hier in dieser Klammer angedeutet habe, ja,
die wird hier genau Betrag von V minus eins mal ausgeführt.
In dieser Vorschlag waren wir eine weitere Vorschleife, hier wird jede Kante einmal betrachtet.
Das ist die zweite Vorschleife hier, ja, die betrachtet jede Kante.
Einmal und darin machen wir nichts weiter als unsere Relaxationsoperation.
Wir gucken also, ob der kürzeste Pfad, den wir
bereits gefunden haben, zu dem Punkt, zu dem Knoten.
U, plus die Kante von U nach V in der Länge kürzer ist,
als der kürzeste Pfad, den wir schon berechnet haben für Knoten V.
Und wenn dem so ist, dann würden wir die Werte für V aktualisieren.
Gut, das machen wir. Betrag von V minus 1. Mal.
Und wenn wir damit fertig sind, müssen wir noch gucken,
ob wir vielleicht einen negativen Zyklus haben,
weil dann wären die Werte nicht korrekt.
Und dann hätten wir Knoten damit mit Entfernung minus unendlich.
Das berechnen wir hier nicht korrekt, sondern wir markieren dann entsprechend nur,
dass die Ausgabe nicht korrekt Ja, also das kann man reparieren.
Also man kann dafür sorgen, dass in dem Fall auch die
richtige Ausgabe produziert wird. Hier machen wir das nur so,
dass wir dann sagen, okay, das ist Falls.
Woran kann man das jetzt erkennen, dass der Bellmann-Ford-Algorithmus
negative Kreise oder Zyklen mit negativer Gesamtlänge entdeckt hat?
Das kann man ganz leicht daran erkennen, indem man einfach
noch ein weiteres Mal alle Kanten anschaut, nachdem der Algorithmus fertig ist.
Und wenn es dann eine Kante gibt,
die zu einer weiteren Verkürzung einer Distanz führt, dann wissen wir,
dass wir einen kürzesten Pfad der Länge V plus 1 gefunden haben,
oder der Länge heißt das bezüglich der Anzahl der Kanten,
der Länge V gefunden haben.
Also es sind V minus 1 Durchläufe hier.
Hier machen wir dann den Fautendurchlauf, also den Nächsten.
Und dann hätten wir für V, also einem Pfad der Länge Betrag von V.
Und wenn das Betrag von V viele Kanten sind,
dann sind entlang dieses Pfades,
haben wir dann Betrag von V
plus 1. Viele Knoten
Und wenn wir so viele Knoten haben, haben wir
einen Zyklus, weil irgendein Knoten muss ja doppelt vorkommen.
Das heißt, wir haben irgendwo entlang dieses Pfades einen Zyklus.
Und wenn das zu einer Verkürzung geführt hat, dann muss
dieser Zyklus negative Kantenlänge haben. Daran können wir erkennen,
ob wir einen negativen Zyklus haben und dann sagen wir einfach,
okay, das Ergebnis ist nicht korrekt. Ja,
hier ist ein Beispiel, wie der Bellmann-Ford-Algorithmus arbeitet,
auch wenn man am Anfang so den Eindruck hat,
der geht jetzt einfach so chaotisch in irgendeiner Reihenfolge durch diese Kantenmenge durch.
So ist es doch so, dass wenn man das Beispiel anschaut,
die kürzesten Wege sich natürlich von dem Startpunkt S aus in dem Grafen sofort pflanzen.
Das liegt einfach daran,
weil die D-Werte am Anfang ja alle noch unendlich sind oder viele sind davon noch unendlich,
also alle bis auf S und wir natürlich bei einer Relaxationsoperation einer Kante zwischen zwei Knoten,
die beide noch den Wert unendlich haben, keine Veränderungen hervorrufen.
Wir haben ja keine Verkürzung, indem wir unendlich plus 5 ausrechnen.
Das wird natürlich nicht kürzer, als das unendlich,
was wir vorher schon hatten. Das heißt,
Aktualisierung oder bessere D-Werte erhalten wir nur, wenn der Knoten,
von dem wir ausgehen,
sondern wird kleiner als unendlich
Und deswegen propagieren sich die kürzesten Pfade tatsächlich von dem Startknoten aus
hier in den Grafen, in jeder Iteration so vorwärts.
Und ja, wie man das Beispiel hier lesen muss,
ist, also das ist der Beispiel, Graf,
in den Knoten selber hier steht jetzt der D-Wert drin.
Ja, also das ist der Initialisierungszustand.
Der Startknoten hat den Wert. Null. Die Knoten T
XY und Z haben jetzt alle noch den Wert unendlich.
Und ja, das sind die Kanten.
Wir haben mal so ein paar Bekannten mit negativen Kantengewichten hier
Nachdem jetzt die erste Iteration durchgelaufen ist, haben wir alle Kanten einmal betrachtet.
Und wir haben die folgende Situation, die hier rauskommt,
und zwar bezüglich dieser Kante hier zwischen S und T,
haben wir die, war die Relaxation erfolgreich.
Wir haben gesehen, dass die bisherige Entfernung DET,
die war unendlich, größer ist,
als wenn wir DS plus diese Kantenlänge sechs nehmen,
was ja sechs ist.
Und dann schreiben wir diese sechs da rein.
Und das Gleiche gilt für diese Kante und dann würde hier
die sieben
drin stehen
Die beiden Werte sind beide noch unendlich zu diesem Zeitpunkt.
Der Bellmann-Fordalgorithmus hat ja, ist ja nicht vollständig spezifizfiziert.
Er hat ja Freiheitsgrade. Und zwar in dieser Vorschleife.
In dieser Vorschleife geben sie ja nicht an,
in welcher Reihenfolge sie diese Kanten betrachten.
Für die Korrektheit des Algorithmus ist das auch egal.
Also für die Korrektheit ist es völlig wurscht,
in welcher Reihenfolge sie die Kanten betrachten.
Deswegen steht da auch, dass nicht da dabei,
dass man es in der speziellen Reihenfolge machen sollte.
Für unser Beispiel wäre das jetzt aber schon relevant.
Wenn wir zum Beispiel die Kante von S nach Tee
zuerst relaxieren und dann die von T nach X,
dann würde auch an der Stelle X jetzt schon ein Wert drin stehen.
Also das Beispiel hier folgt nicht quasi deterministisch aus der Beschreibung des Algorithmus.
Das könnte auch anders aussehen, je nachdem, in welcher Reihenfolge sie das machen.
Es ist nur, wenn sie das mal nachvollziehen und selber erst mal durchgehen,
dann haben sie zufällig eine andere Kantenreihenfolge, dann sieht es schon anders aus.
Was sie aber wissen ist, ist,
dass wenn sie eine gewisse Iterationszahl erreicht haben,
dann wissen sie schon mit einer dann wissen sie schon genau,
dass sie alle kürzesten Pfade, die aus weniger als diese I vielen Kanten bestehen,
dass sie die schon gefunden haben, ausgehend von S.
Also wenn der kürzeste Pfad von S zu irgendwie T oder Y,
wenn der aus nur einer Kante besteht, dann haben sie den zu diesem Zeitpunkt auch garantiert gefunden. Ja,
in der nächsten Iteration betrachten sie jetzt wieder alle Kanten in irgendeiner Reihenfolge und dann würden sie auch entlang dieser Kanten hier relaxieren,
unter anderem und sie hätten dann für X und Z ebenfalls erste Werte hier,
da kommt dann 4 und 2 raus, ja, zwei,
wenn sie diese Kante hier relaxieren mit dem Gewicht minus vier und hier oben kommt der Wert 4 rein,
wenn sie diese Kante relaxieren mit der Entfernung minus drei,
ja, dann haben sie sieben plus minus drei,
dann kommen sie zu dem Wert 4. Sie relaxieren natürlich auch andere Kanten,
die also nicht zu einer Verkürzung führen.
Auch können in einem Durchlauf zwei Kanten-Ding zu einer Redaxierung des gleichen Knoten führen.
Also wenn sie zum Beispiel zuerst diese Kante von Tee nach X betrachtet hätten,
dann hätten sie jetzt gesehen, aha,
6 plus 5 ist 11, ist kleiner als unendlich,
also könnten sie elf reinschreiben, das wäre das erste Mal,
dass der Wert sich ändern würde,
wenn sie zu einem späteren Zeitpunkt die Kante von von Y nach X betrachten,
dann würde dann der Wert auf 4 reduziert.
Machen Sie das in der anderen Reihenfolge,
steht dann nachher natürlich auch 4. Sie hätten dann diesen Wert zuerst gefunden und
die Relaxation der Kante von T nach X wäre dann nicht erfolgreich gewesen.
Das heißt, Sie hätten sie dann den Wert 11 bestimmt,
wäre größer als den kürzesten Pfad, den Sie schon haben,
dann würde sich halt nichts ändern.
Ja, und dann machen Sie das so weiter und nach vier Iterationen,
wir haben fünf Knoten, das heißt vier Iterationen werden benötigt,
haben wir dann das folgende Ergebnis.
Die Entfernung zu diesem Knotentee hier, die hat sich in der dritten Iteration nochmal verändert.
Ja, wir haben jetzt den Wert 2 hier,
der kürzeste Fahrt läuft von S über Y nach X und dann zu T. Sie sehen,
wir brauchen tatsächlich auch drei Kanten, um diesen kürzesten Pfad zu beschreiben.
Ja, und dementsprechend können wir das auch erst in der dritten Iteration hier,
na, das stimmt nicht ganz,
wir finden es garantiert in der dritten Operation,
in der dritten Iteration des Bellmann-Ford-Algorithmus,
wir hätten es mit ein bisschen Glück vielleicht etwas früher finden können,
ja,
aber hier finden wir es spät,
Okay, und das ist dann das Endergebnis und mit einer weiteren Iteration
könnten sie jetzt überprüfen, ob sie negative Kantengewichte haben.
Ja, das ist der Bellmann-Ford-Algorithmus. Hier ist zusammengefasst,
sind die Struktur des Korrektheitsbeweises, den führe ich hier ebenfalls nicht.
Können Sie gerne auch im Kommen mal nachlesen oder wenn Sie
meine Folien aus der Drittsemesterveranstaltung haben, können Sie das da auch angucken.
Also, wie beweist man das? Also der erste Schritt ist,
wir zeigen die korrekte Berechnung von Delta SV, immer dann,
wenn der Wert kleiner ist oder zwischen null und unendlich ist
Und das Lämmer besagt, das angenommen G enthält keine von S aus,
erreichbaren negativen Zyklen. Dann gilt für einen von S
aus erreichbaren Knoten VD von V ist gleich Delta SV.
Der Beweis ist dieser Induktionsbeweis über diese Iteration,
wo man dann zeigen kann, dass man nach der Iten-Iteration
die kürzesten Pfade mit maximal i vielen Kanten gefunden hat.
Dann die Schlussfolgerung, die nächste hieraus ist,
dass die korrekte Berechnung erfolgt für alle Werte,
die für die Pfade existieren.
Das heißt, für jeden Knoten V gilt,
wenn es einen Pfad gilt,
dann ist D von
Kleiner, unendlich. Und es ist eine genau dann Van-Beziehung.
Das heißt, wenn es keinen Pfad gibt,
dann ist das D von V auch gleich unendlich.
Und das Theorie im 24, 4 hier beschreibt dann
die Korrektheit des Bandmann-Ford-Algorithmus, enthält zwei Teile. Erstens,
geh enthält keine von S,
wenn geh keine von S aus erreichbaren negativen Zyklen enthält,
dann gilt erstens für alle Knoten V gilt,
dass die Distanz korrekt dem kürzesten Pfaddistanz entspricht.
Das GP, der Baum der kürzesten Pfade ist und dass der Rückgabe wer true ist
Und wenn negative Zyklen auftreten, dann ist der Rückgabewert voll.
Das muss man hier also noch zeigen. Das ist dann
auch auf alle Fälle passiert. Okay, der Algorithmus intuituitiv
richtig funktionieren sollte, ist, glaube ich, klar geworden.
Der formale Beweis, wie gesagt, in sieben Zweifels war nochmal nachlesen.
So, zwei klassische, kürzeste Pfade-Algorithmen schauen wir noch an.
Auch im Wiederholungsmodus. Der erste, den wir uns jetzt
noch anschauen, ist kürzeste Pfade in Decks,
also in gerichteten abzyklischen Grafen
Und hier ergibt sich eine Beschleunigungsmöglichkeit aus der Tatsache heraus,
dass der Deck ja keine Zyklen enthält.
Also insbesondere können auch keine Zyklen negative Länge existieren,
aber es existiert überhaupt keine Zyklen. Und das können wir ausnutzen,
weil wir die Knoten jetzt nur in der richtigen Reihenfolge betrachten müssen,
um dafür zu sorgen, dass die Kanten in allen möglichen Reihenfolgen relaxiert werden.
Was wir machen ist, wir betrachten die topologische Sortierung mehr Knoten.
Ich hoffe, Sie erinnern sich dran, ja,
also topologische Sortierung ist in einer Reihenfolge, sodass alle kannten,
von einem Knoten niedriger Nummer zu einem Knoten höherer Nummer laufen.
Wir betrachten die Knoten jetzt in dieser Reihenfolge und wenn wir das machen,
dann gilt für, also und dann für diese Knoten relaxieren wir alle ausgehende Kanten.
Und wenn wir das machen, dann ist schon sichergestellt,
dass wir die Kanten entlang aller möglichen Pfade relaxieren.
Warum ist das so? Weil wir ja wissen,
dass entlang dieses Pfades bei der topologischen Sortierung die Knoten weiter,
die weiter links stehen,
tatsächlich immer eine kleinere topologische Nummer haben,
als sie die weiter rechts stehen
Und weil wir dann, die Kanten,
die von dem Knoten weiter links ausgehend zuerst relaxiert haben,
haben wir die in der richtigen Reihenfolge relaxiert. Das bedeutet,
wenn wir ein Deck haben,
dann können wir diese sehr aufwendige Schleife in den Bellmann-Ford-Algorithmus,
die hier, diese Zeile 2, wo wir sagen,
wir gehen einfach die Kantenliste, nminus eins mal durch,
nur um sicherzustellen, dass wir alle möglichen Reihenfolgen haben,
die können wir weglassen, wenn wir vorher die Knoten topologisch sortieren.
Das machen wir also, wir initialisieren unser Single-Source-Problem.
Wir rufen eine topologische Sortierfunktion auf. Da haben wir
zwei Varianten gesehen. Zum Beispiel können Sie in der Tiefensuche
verwenden, um die Knoten topologisch zu sortieren.
Wenn Sie das dann gemacht haben, gehen Sie diese Liste.
Wir gehen davon aus, Sie stehen jetzt in so einer
Liste durch, von vorne nach hinten. Das heißt,
Sie nehmen einen Knoten, das ist der Head,
also der Kopf dieser Liste.
Den Kopf löschen Sie dann aus der Liste heraus.
Und dann gehen Sie durch die Addizenzliste dieses Knotens und relaxieren
alle Kanten. Dieser Algorithmus löst das kürzeste Wegeproblem auf Decks
Macht das in linde Jahrer Zeit. Wir wissen,
mit der Tiefensuche können wir die topologische Suche in AO von N plus M durchführen.
Wir haben die Initialisierung hier, Schritt 1,
die läuft in Linearzeit, also in O von N-Anzahl Knoten.
Wir haben diese Wild-Schleife hier und in der Wild-Schleife,
das ist jetzt so ähnlich wie das Argument bei der Tiefensuche auch,
diese Wild-Schleife geht natürlich über N, viele Knoten, über jeden Knoten.
Und darin betrachten wir immer
die Addizenzliste
Könnte natürlich wieder eng lang sein, aber wir haben natürlich nicht eng Quadratzeit,
sondern nur M-Zeit, also Anzahl Kanten,
weil summiert in diesen beiden Schleifen jede Kante nur einmal betrachtet werden muss.
Deswegen kommen wir insgesamt auf eine Zeit von O von N plus M,
also Linearzeit zur Berechnung, kürzester Pfade, Index.
Das Wichtigste an dieser Stelle ist,
das im Hinterkopf zu haben und wenn sie irgendwann in ihrem Leben über ein kürzeste Wegeproblem stolpern,
ist das allererste immer einen kurzen Augenblick darüber nachzudenken,
ob der Graf vielleicht ein Deck ist,
wenn er ein Deck ist,
ist das natürlich die Methode der Wahl
Ja, der Algorithmus funktioniert übrigens auch bei negativen Kantengewichten.
Das heißt, während der Deikstra-Algorithmus da noch streiken würde,
kann der Algorithmus problemlos auch in diesem Fall angewendet werden.
Negative Zyklen können ja nicht auftreten, weil wir haben ja
keine Zyklen. Und die Art und Weise,
wie der Algorithmus dann funktionieren würde, ist, naja,
also wenn sie die topologische Sortierung haben und hier ist unser Startknoten S,
der ist jetzt hier an dieser Position 2.
Die Knoten sind aufgeschrieben, entlang der topologischen Sortierung.
Ja, das heißt, die Kanten laufen immer von links
nach rechts
Und bis zu dem Knoten S können sie alle Knoten,
LED-Werte dieser Knoten einfach auf unendlich belassen.
Die müssen die eigentlich gar nicht betrachten, wenn sie so wollen,
weil, naja, ausgehend von einem Knoten mit dem D-Wert
unendlich können sie natürlich auch keine Relaxation durchführen.
Sie kannten Fade eng werden, dadurch nicht kürzer. So,
und dann sind sie bei dem Knoten S angekommen hier,
wenn sie den jetzt relaxieren im nächsten Schritt,
dann betrachten sie die von S auslaufenden Canten.
Diese und diese relaxieren die,
kriegen dann die ersten D-Werte für die Knoten hinter S,
also Tee, würde er die jetzt die Entfernung 2 haben sind wir als sechs.
Und dann nehmen sie den nächsten Knoten Tee hier,
der hat die Entfernung zwei und würden wieder alle Kanten relaxieren.
Diese Kante hier würde zu keiner Verkürzung führen, weil zwei plus sieben,
neun wäre also länger als den kürzesten Pfad, den wir schon haben.
Über diese beiden Kanten können wir relaxieren und erhalten dann für Y
und für Z die Pfadlängen zwei, zwei plus vier,
macht sechs und zwei plus zwei, macht vier.
Und im nächsten Schritt würden wir dann den Knoten x relaxieren,
der hat ja die Kantenlänge minus eins,
dadurch reduziert sich der Wert für den Knoten Y hier
auf fünf
Und ja, das geht dann so weiter. Und am Ende haben wir dann hier die D-Werte,
die den kürzesten Pfadlängen entsprechen und in Rot markiert wieder die Kanten, die den kürzesten Pfadbaum beschreiben.
Vielleicht sollte man an dieser Stelle nochmal sagen, dass,
wenn wir diesen Baum hier betrachten, die Art und Weise,
wie die Kanten gespeichert werden, normalerweise andersherum ist.
Also es kann am Anfang ein bisschen verwirren. Also man würde jetzt erwarten,
dass wir jetzt irgendwie speichern,
es gibt diese Kante von S zu X,
aber die Art und Weise, wie es gespeichert ist,
ist, dass wir uns von X aus merken,
welche Kante müssen wir durchlaufen,
um zum Vorgänger
zu kommen
Ja, das heißt, die Kanten sind in dieser Relation immer umgedreht gespeichert.
Ja, und dann beschreiben aber natürlich genau das Gleiche.
Gut, okay, das ist also für den Fall,
dass wir Decks haben, eine ganz einfache Situation,
eine ganz effizientes, schnelles Verfahren um die kürzesten Pfade zu beschreiben.
So, und jetzt, ja, der Klassiker,
der berühmteste Algorithmus für kürzeste Pfade. Ich würde sogar sagen,
es ist vielleicht der berühmteste Algorithmus aus der Informatik überhaupt,
ja.
Das ist der Deikstra-Algorithmus
Der kürzeste Pfade berechnet für den Fall, dass wir nicht negative Kantengewichte haben.
Das ist also die ganz zentrale Einschränkung, die gelten muss,
die allerdings für die allermeisten Anwendungen keine so große Rolle spielen,
weil wir in der Praxis ganz häufig die Situation haben,
dass wir positive Kantengewichte haben, weil eben unsere Entfernungs,
ja,
unsere Modellierung von Entfernung in der Regel eben positiv sind.
Gut, wir haben eine Menge S, in der speichern wir alle Knoten,
deren kürzere ist die Pfade bereits berechnet worden sind.
Am Anfang ist dann nur der Startknoten drin. Beachten Sie,
dass diese Menge S streng genommen eigentlich gar nicht nötig ist.
Die führen wir hier mit. Und die brauchen wir nur,
um sie nachher zu einem Korrektheitsbeweis zu benennen.
Also wenn es ihnen nur darum ging,
den Algorithmus zu implementieren, dann sehen Sie zur Berechnung,
benötigen Sie das S überhaupt nicht.
Das wird irgendwann mal mit leerer Menge initialisiert und dann kommen die Knoten da rein.
Aber sie brauchen das für die Berechnung hier eigentlich gar nicht.
Ja, viel entscheidender ist die Schlange Kuhuhu ist eine Prioritätswarteschlange
Die initialisiert wird, mit der Knotenmenge. Das bedeutet,
dass am Anfang bereits alle Knoten in dieser Cue drinstehen,
dass es auch eine Beschreibungsform, die so nicht sein müsste.
Es gibt also die praktische Implementierung ist normalerweise auch anders,
in der praktischen Implementierung würde man in diese Warteschlange zunächst nur
den Knoten S reinschreiben und dann nach und nach die anderen Knoten einfügen.
Hier ist die Beschreibung eben anders, also am Anfang sind
schon alle Knoten da drin und das ist eine Prioritätswarteschlange,
die Priorität als Priorität, die obere Schranke D von V verwendet.
So, da sind jetzt also alle Knoten drin.
Und weil nur der Startknoten ist in D-Wert 0 hat,
wissen wir, dass dieser Knoten am Anfang der Prioritätsschlange steht und alle anderen Knoten haben den Wert unendlich.
Ja, solange diese Schlange jetzt nicht leer ist,
holen wir uns hier das Minimum aus der Schlange heraus.
Und wir fügen dann diesen Knoten in die Menge S ein und markieren damit,
dass wir den kürzesten Pfad für diesen Knoten bereits berechnet haben.
Und dann kommt Ja, die Vorschleife, die alle Kanten sondiert.
Wir betrachten also alle Kanten aus der Addizenzliste von U und führen eine Relax-Operation durch.
Im Kormen steht dann da auch nur Relax. Tatsächlich,
ich habe das hier geändert, habe da relaxed die Crease geschrieben,
weil das Entscheidende an dieser Stelle ist,
dass so eine Relax-Operation ja den D-Wert verändert, also kann.
Also wenn ja die Entfernung für den Knoten V über diese Kante UV kürzer wird,
dann ändert sich ja der D-Wert, diese Schranke wird reduziert.
Und das impliziert, dass in der Relax-Operation in der Warteschlange Kuh,
die Position dieses Knotens verändert werden muss.
Der wandert in der Schlange ja weiter nach vorne in diesem Augenblick.
Das ist im Kormen so ein bisschen kaschiert. Da geht man dann davon aus,
ja klar, also der steht ja jetzt in der Datenstruktur drin,
der Knoten und wenn ich den D-Wert verkleinere,
dann wird der wohl auch weiter nach vorne rutschen.
Das finde ich insofern ein bisschen unschön,
weil genau hier die Komplexität entsteht, dadurch,
dass man die Warteschlange immer wieder anpassen muss und das so
explizit dann in dem Pseudo-Code nicht drinsteht und weil es auch fern ist von der Art und Weise,
wie man sowas implementiert.
Deswegen habe ich es mal so aufgeschrieben,
also hier steht explizit
das D-Quiz-Key
Also in der Praxis, bei der praktischen Implementierung,
würden Sie hier nur mit dem Essknoten anfangen.
Das ist sogar effizienter, nicht asymptotisch effizienter,
aber in der Praxis effizienter, weil diese Operation,
dann ein X-Track-Min und ein Deekries-Key, sind natürlich,
hängen logerithmisch von der Anzahl der Knoten in der Warteschlange ab.
Und wenn ich schon am Anfang alle Knoten reingeschrieben habe,
dauert das immer Log-End-Zeit.
Wenn ich aber am Anfang weniger Knoten drin habe,
würde zumindest zu Beginn dieses Algorithmus diese Operation,
diese beiden Operationen schneller ablaufen.
Also im Tote spielt das keine Rolle,
aber praktisch eben schon
Okay, das ist der Da-Extra-Algorithmus. Zur Berechnung kürzester Pfade
. Und ja, hier ist ein Beispiel,
das ist der Graph quasi fast der gleiche wie eben,
außer dass ich ein paar Kantengewichte geändert habe, sodass die alle positiv sind.
Und ja, am Anfang betrachten wir diesen Knoten S,
der ist der einzige mit einem D-Wert kleiner als unendlich.
Steht also am Anfang dieser Prioritätswarteschlange. Alle anderen,
die stehen jetzt hier hinter, das ist die Prioritätswarteschlange hier.
Und in einer x-beliebigen Reihenfolge, weil Entfernungswert ist unendlich,
es spielt also keine spezielle Ordnung hier. Und jetzt würden wir also S betrachten,
wir relaxieren die von S ausgehenden Kanten, 5 und 10,
also mit dem Kantengewichten 5 und 10,
Y und T bekommen jetzt neue D-Werte, weil die Relaxation hier erfolgreich war.
Und dadurch ändert sich die Reihenfolge in der Prioritätswarteschlange,
also S wird entfernt, haben wir ja bearbeitet.
Y ist der Knoten mit dem kleinsten D-Wert,
der rutscht also jetzt nach vorne in der Prioritätswarteschlange,
danach kommt der Knotentee und dann X und Z,
weil die nach wie vor unendlich sind.
Ja, dann würden wir Y als nächstes bearbeiten,
wir betrachten wieder alle Kanten,
die Y verlassen
Das führt zum Beispiel dazu, dass wir diese Kante hier relaxieren,
die für den Knoten Tee einen neuen D-Wert berechnet, acht,
der würde also den Wert hier verringert von zehn runter auf acht.
Aber wir kriegen auch über diese Kanten hier von Y nach X
und von Y nach Z entsprechend neue D-Werte für die Knoten
hier X und Z. Und die Prioritätswarteschlange sorgt eben dafür,
dass diese jetzt so immer sortiert sind,
dass vorne der Knoten steht mit dem kleinsten D-Wert
Okay, so, ja,
als nächstes würden wir dann den Knoten-Set hier bearbeiten,
würden wir die Kanten relaxieren und ich glaube,
es ist klar, wie das dann weiterläuft,
der Knoten X hier wird im Wert nochmal reduziert,
es ändert aber nichts in seiner Position,
dann wird Tee hier entsprechend betrachtet,
alle Kanten relaxiert der Knoten X-Rick, nochmal einen kleineren Wert,
dann wird der Knoten X als letztes bearbeitet und wir sind fertig.
Okay, das ist der Ablauf,
wie funktioniert der Korrektheitsbeweis, also das Theorien zur Korrektheit
des Dikes-Algorithmus besagt
WNG, ein gerichteter Graf mit einer Gewichtsfunktion W von E nach R 0 Plus ist.
Das heißt, wir haben reellwertige Kantengewichte, die aber größer
gleich null sein müssen. Es ist ein beliebiger Startknoten,
dann gilt nach Terminierung des Diexalgorithmus für alle Knoten,
U, D von U, gleich Delta, SU.
Also, dass er die Kanten korrekt berechnet. Auch den Beweis werde ich
hier nicht machen. Es passiert auch bereits in der Drittsilvesterveranstaltung,
nur noch mal die Beweisidee,
weil sowas ähnliches werden wir dann heute auch noch mal sehen,
man macht, ist, man überlegt sich,
es gibt eine Menge von Knoten, S,
für die wir schon die Länge des kürzesten Pfades korrekt berechnet haben.
Und dann gibt es eine Menge N, die Menge N,
das sind Knoten, wo der D-Wert schon kleiner ist als unendlich,
die aber nicht in der Menge es sind und N,
das entsteht für Nachbarschaft.
Das sind die Knoten, die wir von S aus mit einer Kante hier erreichen können.
Die haben einen D-Wert, der kleiner ist als unendlich.
Und dann gibt es den ganzen Rest,
das ist diese Menge A,
das sind die anderen und das sind alles Knoten,
die eben über mehr als zwei als eine Kante von
der Menge S
entfernt ist
So, und was sie jetzt machen, ist, dass sie sich eine etwas definieren.
Und zwar sagen sie sich, wir definieren mal Delta oben S.
Und das sind die Länge der kürzesten Pfade,
die nur Knoten aus der Menge S enthalten.
Die also nicht hier irgendwelche anderen Knoten betrachten. Und was sie dann zeigen können,
ist, dass während diese Wildschleife läuft,
für alle Knoten aus S gilt,
also die, die hier drin sind,
dass sie den kürzesten Pfad schon berechnet haben und für alle Knoten aus N gilt,
dass sie den kürzesten Pfad berechnet haben unter der Annahme,
dass er keine anderen Knoten verwendet,
außer die,
die in S
vorhanden sind
Also wenn der kürzeste Pfad zu diesem Knoten so verläuft,
dass er irgendwie sich hier in S bewegt und dann diese
Kante hier durchläuft, dann hätten sie ihn schon berechnet.
Also sie benutzen dann nur Knoten aus der Menge S. Wenn er hier woanders langläuft,
zum Beispiel hier, hier könnt ihr auch sein,
ja, dann haben sie ihn noch nicht berechnet.
Das ist ja sehr unterschiedlich zwischen Delta und Delta oben S. So,
das können sie zeigen, dass das der Fall ist,
dass sie das berechnet haben, das Volk quasi durch dieses schrittweise Relaxieren dieser Kanten.
Und jetzt kommt die eine entscheidende Operation,
auf die die Korrektheit des Algorithmus fußt, und zwar die Tatsache,
dass der nächste Knoten, den sie wählen,
für die Relaxation, ist der Knoten mit minimalem D-Wert.
Und weil das der ist mit dem kleinsten D-Wert, es ist automatisch der,
der auch am dichtesten an den Knoten hier dran ist.
Also bezüglich der kürzesten Fahrtlänge. Und für den Knoten,
nur für diesen einen Knoten, uh, mit dieser Eigenschaft wissen sie,
dass sie für diesen Knoten bereits die korrekte kürzeste Pfadlänge berechnet haben müssen,
weil die kannten alle positive Länge haben.
Wenn dieser Knoten der ist,
der am dichtesten an der Menge S dran ist,
dann kann ein Pfad über einen anderen Knoten nicht mehr kürzer werden,
weil dieser Knoten ja schon weiter von S entfernt ist.
Deswegen gilt für diesen einen Knoten, dass sie ihn von
der Menge N in die Menge S übertragen dürfen. So,
und dann müssen sie wieder die Kanten relaxieren,
um dann dann, um sicherzustellen, dass die neue Nachbarschaft,
das sind ja jetzt dann neue Knoten hinzugekommen,
wieder gerade die Eigenschaft hat, dass die Knoten hier die Idee wertete im Delta S von SV bestimmt.
Das ist die Beweisidee hinter der Korrektheit des Dextra-Algorithmus.
Auch das muss man natürlich länger formulieren.
Der Beweis, wie gesagt, machen wir hier jetzt
nicht nochmal
Zur Laufzeit des Diaks und Algorithmus. Wir haben N-Iiterationen der Wirelschleife,
dieser hier, ja, N-Mahl müssen wir das Ganze machen.
In jeder dieser Iterationen müssen wir einmal das Extract Min der Prioritätswarteschlange aufrufen.
Und dann haben wir in der Wirelschleife die Vorschleife,
die die Kanten betrachtet, da wird jede Kante einmal betrachtet in der Summe.
Das sind also M-viele Schleifendurchläufe insgesamt. Und in jeder dieser Schleifendurchläufe haben wir im Prinzip
Im ungünstigsten Fall eine D-Crease-Key-Operation. Und wir wissen,
wenn wir jetzt also für die Prioritätswarteschlange einen Hieb verwenden,
brauchen diese Operationen hier Log-in-Zeit, also wohl das Extract Min als auch,
dass die Crease-E haben Log-in-Zeit bei einem,
bei der Hieb-Implementierung einer Prioritätswarteschlange.
Und daraus resultiert die Gesamtlaufzeit für den D-Extra, das ist N-Log-in plus M-Log-in.
Und weil M vermutlich größer ist als N,
wissen wir, dass das O von M-Log-in ist.
Wir gehen immer davon aus, dass er zusammenhängend ist.
Dann haben wir hier O von M-Log-in
Zeit für den Diextra-Algorithmus. Wir werden genau diese Stelle hier
noch einmal betrachten, wenn wir uns mit Datenstrukturen auseinandersetzen,
weil der Diikstra-Algorithmus einer der Auslöser dafür war,
dass man sich intensiv mit Prioritätswarteschlangen auseinandergesetzt hat,
in der Algorithmik.
Denn wenn man mal guckt, dann ist es eigentlich erstaunlich,
dass lediglich das Durchführen dieser Decrease-Key-Operation,
was die Knoten dem Prioritätswarteschlange so ein bisschen nach oben schieben,
der dominierende Faktor der Laufzeit im Diikstra-Algorithmus ist
Und eine Prioritätswarteschlange, die die Krease-Key-Operation beschleunigt,
wird automatisch kürzere Laufzeiten bei der Berechnung kürzester Pfade.
Wenn Sie das in konstanter Zeit hinkriegen,
dann hätten Sie sofort N-Login plus M,
was eine deutliche Verkürzung der Laufzeit wäre.
Das gilt übrigens nicht nur für den Likes-Algorithmus.
Das gilt auch bei der Berechnung von Spannbäumen,
für den Primen-Algorithmus,
der auch quasi eine Prioritätswarteschlange verwendet an der Stelle.
Der klassische binäre Hieb hat diese Schranken.
Damit erreicht man diese Laufzeiten. Es gibt Hieb-Implementierung,
die werden wir irgendwann im Dezember mal sehen.
Wahrscheinlich erst im Dezember. Die Crease-Key-Operation beschleunigen können, auf konstante Zeit.
Und dann kriegt man eine bessere Laufzeitschranke für den Diexer.
Die Implementierung dieser anderen Hieb, nicht der Heat,
der anderen Prioritätswarteschlangen, das sind sogenannte Fibonacci-Heebs.
Wir werden noch sehen,
die sind rechtskomplex
Die sind zwar asymptotisch tatsächlich besser als der binäre Hieb.
Allerdings haben die hohe Konstanten. Das heißt,
da müssen sie schon auf richtig, richtig großen Grafen arbeiten,
damit sich sowas dann lohnt.
Ja, okay, das war's zum Deixtra.
Und jetzt verlassen wir den Wiederholungsmodus. Und schauen uns mal
Fahrtprobleme zwischen allen Knotenpaaren an. Vielleicht hat der eine oder
andere das auch schon gesehen, weiß ich nicht.
Ich gehe jetzt mal davon aus,
dass nicht
So, also was wollen wir jetzt machen? Wir wollen
mit einem Algorithmus die kürzesten Pfade zwischen allen Knotenpaaren berechnen.
Mich erinnert das immer spontan an etwas,
was man so in älteren so Atlanten und so gefunden hat.
Das gibt es, glaube ich, gar nicht mehr.
Da hatte man halt irgendwo immer so eine Entfernungsmatrix.
Da standen dann irgendwie, da hat man eine Deutschlandkarte,
standen dann irgendwie die 20 größten Städte und da hatte man
so eine Matrix und da stand dann für jede Stadt,
wie weit sie entfernt ist von irgendeiner anderen.
Das wollen wir quasi erreichen. Wir wollen in einem Schritt
quasi alle kürzesten Pfade hat Distanzen in einer Matrix D berechnet.
Und idealerweise hätten wir natürlich gerne auch alle kürzesten Pfade gegeben und
dafür berechnen wir eine Matrix P, die wieder diese Vorgängerinformationen speichert.
Ja, okay, wenn wir alle kürzesten Pfade berechnen wollen,
dann können wir sagen, klar, ist ja kein Problem,
wir haben unseren Diextra-Algorithmus und den lassen wir einfach en-mal laufen.
Wir beginnen mit jedem Knoten einmal als Startknoten, lassen den Diextra-Algorithmus laufen,
berechnen damit alle kürzesten Pfade von diesem Startknoten zu allen anderen
Und wenn wir das dann en-mal gemacht haben,
dann haben wir das Ergebnis berechnet.
Laufzeit von diesem Verfahren, was zugegebenermaßen jetzt nur funktioniert,
bei nicht negativen Kantengewichten, aber das ist vielleicht ja auch der typische Fall.
Wäre dann en-mal N plus M-Log-in. Also hier habe ich
mal N plus M hingeschrieben, weil wir nicht genau wissen,
ob der Graf wirklich verbunden ist. Sie könnten auch sagen,
N mal M-Log-in, das ist auch nicht wirklich falsch.
Wäre die Laufzeit dieses Ansatzes. Ja, und das ist ja,
naja, zumindest wenn man den deichster Algorithmus kennt,
ein relativ Ein naiver Ansatz.
Das ist ganz einfach. Ich rechne das N-Mahl benutze ich den Algorithmus.
Jetzt hat man irgendwie das Gefühl, dass das eigentlich nicht geschickt ist.
Warum? Also ich lasse den da extra Algorithmus laufen und
ich beginne bei meinem Startknoten S. So, jetzt berechne ich
alle kürzesten Pfade von S irgendwie in diesen Grafen hinein.
Also nach hier und nach hier und immer, und hier entsteht so ein kürzester Pfadbaum. Wenn ich das gemacht habe,
dann habe ich ja Nicht nur die kürzesten Pfade von S zu diesen Knoten hier berechnet,
die hier irgendwie am Ende dieses liegen,
sondern ich weiß ja wegen der optimalen Teilstruktur, Eigenschaft kürzester Pfade,
dass wenn hier irgendwo so ein Knoten auf dem Weg liegt,
also wenn hier zum Beispiel der Knoten V lag,
dann ist natürlich auch das Teilstück von V nach,
oh, ein kürzester Pfad.
Und den habe ich ja im Prinzip jetzt indirekt mit berechnet. Eigentlich wollte ich ja nur wissen,
was sind die kürzesten Pfade von S,
aber ich kenne auch die kürzesten,
zum Beispiel den von V nach O,
weil jetzt gerade hier auf dem Weg lag,
wenn ich jetzt zum Beispiel diesen Knoten betrachte, das wäre mal V-Strich,
Dann kenne ich aber nicht die Länge des kürzesten Fahrrades von V-Strich nach U,
weil der gerade nicht in diesem Baum als kürzester Fahrt beschrieben ist.
Das heißt, dieser hier, das ist unbekannt,
aber den hätte ich schon mit berechnet. Das heißt,
der Deikstra-Algorithmus berechnet eigentlich mehr, aber wir können es nicht
so genau beschreiben, was er wirklich berechnet.
Und deswegen müssen wir ihn dann ein Mal ausführen.
Aber man hat so das Gefühl, da ist irgendwie Redundanz dran.
Wir berechnen irgendwas erscheinbar zu viel, weil irgendwann werden ja
den Knoten V als Staatknoten betrachten in dem Deikstra-Algorithmus.
Und dann würden wir nochmal die kürzesten Fahrt von V
nach U berechnen
Ist ja irgendwie blöd. Den kennen wir im Prinzip schon. Das heißt,
hier ist eigentlich die Hoffnung da, dass das besser gehen muss,
als N mal einfach den Dikestra-Algorithmus zu berechnen.
Mir ein ehrlicher Mensch, wir werden uns verdammt schwer tun,
das in der Laufzeit wirklich zu verbessern.
Okay. Ja, was ist passiert,
wenn wir nicht negative Kantengewichte, also wenn wir negative Kantengewichte haben,
dann müssten wir den Bellmann-Ford-Algorithmus verwenden.
Der hat ja N mal M-Laufzeit und dann kämen wir
auf N-Quadrat mal M. Laufzeit hier insgesamt
Ja, gut, bevor wir mal schauen,
ob wir Algorithmen finden, die in einem Schritt das Ganze berechnen,
müssen wir erst mal noch mal überlegen, wie wir jetzt vorgehen,
wie wir insbesondere die Informationen speichern wollen.
Wir wollen ja nicht eng mal so einen Baum hier speichern,
dann hätten wir auch ein ziemlich große Ausgabe,
sondern wir wollen es irgendwie ein bisschen kompakter machen.
Wir werden also jetzt im Wesentlichen mit Matrizen arbeiten,
in denen wir die Atdiatienzen speichern,
also die Nachbarschaften in dem Grafen und auch nachher
die Pfade speichern werden
Wir machen das wie folgt. Wir gehen also nicht
von Atjazenzlisten aus im folgenden, sondern von einer Atjazenzmatrix.
Das ist diese W-Matrix und eine Position und W-I-J beschreibt dann
eben null, wenn Knoten I und J identisch sind.
Also die Indizes hier sind Knoten.
Also wenn die identisch sind, ist der gleiche Knoten.
Und wenn eine Kante von Knoten I nach J verläuft,
dann schreiben wir da eben das Gewicht rein.
Und wenn es keine Kante gibt von I nach J,
dann schreiben wir da unendlich rein.
Das ist jetzt quasi die Notation. Da können wir in
einer Beschreibungsform in einer Matrix sowohl die Atjazenzinformation als auch
die Kantenlängen wiedergeben
Okay, wenn man Algorithmen entwirft, muss man immer
als erstes überlegen, wie groß ist die Ausgabe?
Weil die Größe der Ausgabe definiert schon eine untere Schranke für die Laufzeit,
die wir erreichen können. Wenn die Ausgabe sehr groß ist,
dann müssen wir die ja produzieren und dann können wir es
nicht effizienter machen als die Zeit, die wir brauchen,
um die Ausgabe zu produzieren.
Was wir tun werden, ist,
wir können alle kürzesten Distanzen in dem Graf speichern,
in einer Matrix.de,
das ist eine N-Mal-N-N-Matrix und damit hätten wir einen Platzbedarf
von N-Quadrat
Wir haben ja, das ist ja quasi unsere Fragestellung,
dass wir alle Paarweisen kürzesten Distanzen wissen wollen.
Das sind nun mal Endquadrat viele. Und deswegen müssen wir
die alle ausgeben, produzieren und ausgeben.
Und da brauchen wir auch Endquadrat viel Platz.
Und damit haben wir auch eine untere Schranke.
Also wir wissen besser als Endquadrat können wir eigentlich nicht werden.
So, jetzt gucken wir noch mal schnell zurück.
Also das hier ist N-mal M-Log-N-M. Wenn wir mal davon ausgehen,
dass der Graf dünn ist, also wenig Kanten hat,
wie zum Beispiel Straßennetzkarte oder so,
dann wäre M ungefähr noch in der Größenordnung von N,
dann würde sowas stehen wie
Das ist nicht viel größer als diese untere Schranke von Endquadrat, die wir sowieso brauchen.
Das ist jetzt das Nächste, was man feststellt.
Also der Deixtra-Algorithmus scheint irgendwie Dinge dann doppelt zu berechnen,
aber auf der anderen Seite ist die Gesamtlaufzeit kaum länger als die untere Schranke,
die wir haben. Wenn der Grafin gegen dicht ist,
also dicht heißt, wir haben mehr als Omega von En,
viele Kanten in dem Grafen,
also das ist eine ganz hoher Vernetzungsgrad,
dann wäre das M eher so wie En ein Quadrat und
dann steht hier sowas wie En hoch 3 Login und dann scheint doch wohl ordentlich noch Luft zu sein,
zwischen dieser Endquadratgroßen Ausgabe
Okay, so. Wie speichern wir jetzt die kürzesten Pfade?
Wir wissen, wir haben das Kriterium der Optimalität von Teilpfaden.
Das heißt, wir müssen uns eigentlich immer nur,
genau wie wir das beim Diextra auch gemacht haben,
wir müssen es immer nur ein Vorgänger merken, entmerken dieser kürzesten Pfade.
Und das können wir auch beim All-Pairs-Problem machen,
indem wir einfach sagen, wir haben so ein Knotenpaar IJ.
Ja, wir haben also jetzt diese Matrix,
wo wir die Vorgänger speichern werden.
Und da haben wir irgendwie so eine Position IJ.
Und hier schreiben wir etwas rein,
einen Wert
Und dieses PEJ sagt uns,
wenn wir den kürzesten Pfad von I nach J suchen,
dann ist die letzte Kante, die wir betrachten,
das, was in diesem Feld drinsteht.
Also wir haben irgendwie unseren Knoten I, wir haben diesen
kürzesten Pfad zu dem Knoten J. Und die letzteste Kante entlang dieses Pfades,
das geht hier vielleicht zu diesem Knoten K,
diese Kante hier, die merken wir uns,
indem wir sagen, von welchem Knoten sind wir denn gekommen?
Und das hier ist das genau, dieses PEJ,
was setzen wir dann auf diesen Wert K
Okay, also, das ist diese Matrix P,
die wir verwenden, wenn also K,
der Vorgänger von J auf einem kürzesten Pfad von I nach K,
dann zu J ist,
dann wissen wir,
dass die Pfadlänge,
die kürzeste Fahrtlänge IJ die ist natürlich die kürzeste Fahrtlänge von I
nach K plus die Kante von KJ und wir können dann rekursiv die kürzesten Pfade rekonstruieren und wir merken uns diesen Vorgänger in dieser Matrix PP,
J wird auf K gesetzt,
genau dann,
wenn wir diesen kürzesten Pfad haben und sonst steht da Neil drin,
wenn wir also
keinen Pfad haben
Okay, wir können jetzt aus,
das ist ja im Prinzip ein Graf, den wir haben,
den wir hier beschreiben mit diesem Pea und da können wir einen,
wir können einen Teilgraf daraus rekonstruieren,
indem wir uns mal einen Knoten raussuchen, einen speziellen Knoten I,
den suchen wir uns mal raus und bilden dann den folgenden Grafen,
wir sagen,
wir nehmen mal alle Knoten aus unserem ursprünglichen Grafen V heraus,
die die Eigenschaft haben, dass dieser Pea-Wert ungleich Nil war,
da stand was drin.
Wenn da was drinsteht, dann wissen wir,
es gibt einen kürzesten Pfad
Also was wir also extrahieren in diesem Vorgänger-Teilgraf sind quasi in der Knotenmenge
alle Knoten, die wir erreichen können und den Knoten-I selber.
Den nehmen wir natürlich noch mit dazu. Und die Kanten,
die wir erzeugen,
das sind genau die Kanten zwischen dem PEJ und dem J.
Das ist genau diese letzte Kante entlang des kürzesten Pfades.
Die nehmen wir in unseren Vorgänger-Teilgraf auf. Und was dann passiert ist,
dass wir aus unserer Matrix P, die wir haben,
in einem Schritt für einen speziellen Knoten
diesen Baum,
den Baum der Vorgängerknoten erzeugen
Den können wir in einem Schritt quasi bauen.
Das sollte ich dem Pfeil bis hier waren.
Es ist klar, es ist der Baum ist, ja.
Wer entsteht aus der Matrix P? Ja, das heißt,
wir können direkt aus dieser Matrix hier jeden beliebigen Vorgängerteilgraf erzeugen.
Also jeden beliebigen Baum, den wir auch mit dem Dikes-Ralgorithmus
erzeugt hätten. Können wir direkt ableiten aus diesem Grafen.
Okay, das ist super. Das heißt,
wir können auch alle Pfade, die wir brauchen,
um alle möglichen kürzesten Pfade zu beschreiben,
mit Endquadrat
viel Platzbedarf speichern
Okay, so, wie können wir jetzt dann kürzeste Pfade ausgeben? Mal angenommen,
Sie haben das jetzt alles berechnet, Sie haben jetzt diese Matrix mit diesem PEJ werden,
dann wäre natürlich immer die Frage, okay,
wenn ich jetzt diese Matrix habe, wie kann ich jetzt,
wenn ich wirklich einen kürzesten Pfad haben will,
wie kann ich den jetzt hinschreiben, wie der aussieht?
Das geht ganz einfach mit diesem Verfahren, mit diesem Algorithmus,
der Algorithmus heißt Print All Pairs, Short is Path,
da geben Sie diese Peam-Matrix rein und zwei Punkte,
zwei Knoten I und J und sagen,
und dann machen Sie Folgendes, wenn also I gleich J ist,
dann schreiben Sie nur I auf, dann sagen Sie,
okay, ich jetzt den kürzesten Weg ausgeben will,
dann geht der halt von I nach I und dann ist das nur I.
Und anderenfalls gucken Sie, wenn das PEJ gleich Neil ist,
dann wissen Sie, es existiert überhaupt kein kürzester Pfad,
können Sie auch nichts ausgeben oder Sie geben eine Fehlermeldung aus oder so.
Und anderenfalls rufen Sie die Funktion reklusiv auf und schreiben am Ende das J hin.
Ja, Sie gehen also jetzt zum Reklusiv zu dem Vorgänger,
das ist PIJ. PEJ war ja gerade das K,
den Knoten, den wir vorher gesehen haben, ja,
und dann schreiben Sie noch das J drauf.
Also was Sie hier machen, ist quasi, das ist reklusiv,
das ist aber quasi So eine Endrekursion. Das heißt,
diese Rekursion haben wir nur, damit wir die Kanten oder
die Knoten entlang des Pfades in der richtigen Reihenfolge aufschreiben.
Das heißt, Sie haben jetzt den Pfad hier,
der geht über viele Knoten. Sie starten an dem Knoten J. Dann
gehen Sie zu dem Vorgänger von J. Das sagt Ihnen diese P-Relation.
Dann gehen Sie zu dem Vorgänger, zu den Vorgängern,
zu den Vorgängern, zu den Vorgänger.
Dann sitze ich irgendwie mal bei I angekommen. Und wenn wir
bei I angekommen sind, dann würden wir das ausgeben. Dann würde also,
wenn wir dann hier den Pfad generieren würden,
den Output würden wir jetzt EI hinschreiben und dann würden wir rekursiv zum Aufrufenden,
zur aufrufenden Funktion zurückgeben, würden dann den entlang dieses Pfades, den nächsten Knoten ausgeben.
Das wäre dann hier entsprechend der, ja. So,
und dann geht das immer so weiter und irgendwann würden wir
dann Chaos geben und dann J. Okay,
das ist also die Art und Weise,
wie man aus der Matrix ganz einfach beliebige Pfade ableiten kann.
Das geht in der Länge des Pfades, also in der Länge des Outputs,
was man dann produziert und ist dann optimal.
Ja, das heißt also, mit dieser Pi-Matrix können wir
alles anstellen, was wir wollen.
Wir können den Baum erzeugen für ein Knoten-I,
mit allem kürzesten Fahren.
Wir können jeden x-beliebigen kürzesten Pfad einfach rekonstruieren
Und deswegen ist das eine super Methode,
diese kürzesten Pfade zu speichern. Und wir werden im Folgenden
diese Pi-Matrix erstmal so ein bisschen außen vor lassen.
Wir werden sehen, alle Algorithmen, die sie betrachten,
da können sie die Pi-Matrix immer einfügen und das mitberechnen.
Wir werden jetzt im folgenden primär die D-Matrix berechnen. So,
die erste Erkenntnis, wenn man sich mal überlegt,
wie man vielleicht auch anders vorgehen könnte,
um die kürzesten Pfade zu berechnen,
ist,
dass kürzeste Pfade
im Prinzip mit einer rekusiven Definition beschrieben werden können
Und die steht da. Und zwar ist die Idee ganz einfach.
Das ist auch so ein bisschen so, wie beim Bellmann-Ford-Algorithmus,
den wir ja eben noch gerade noch mal gesehen haben.
Nämlich, dass wir Folgendes tun. Wir haben das,
wir berechnen ein LIJ oben M. und LIJ
OMM ist die Länge des kürzesten Pfades von I nach J.
mit maximal M-Kanten. Ja, das sollte ihn jetzt,
sollte es sofort klingeln,
also Bellmann fort
Das ja so, da hatten wir diese Schleife,
die einfach nur N, minus eins mal wiederholt wurde.
Ja, und da habe ich ja darauf hingewiesen,
dass man immer quasi die kürzesten Pfade bis zu so und
so viel Kanten berechnet hat nach der Iten-Iteration.
Und das macht man hier genauso. Man sagt sich,
okay, wir wollen, wir sagen jetzt einfach mal,
wir berechnen das Schritt für Schritt und diese Schritte,
die wir machen, ist die Anzahl der Kanten,
die der kürzeste Weg haben kann oder hat.
Okay, und dann kann man sich überlegen, wie kann man
das LIJOMM berechnen? Und das ist eigentlich ganz einfach.
Wir überlegen uns zuerst, was ist denn das LIJ oben null?
Also die Länge des kürzesten Pfades von einem Knoten Eat,
zu einem Knoten J über null, maximal null viele Kanten.
Wenn ich keine Kante benutzen darf, dann ist die Situation ganz einfach,
denn entweder I ist gleich J,
dann ist die Länge null, ja,
weil das ist ja die einzige Möglichkeit von einem Knoten zu einem anderen zu gehen,
ohne eine Kante zu benutzen, wenn der Knoten der gleiche ist.
Oder es ist unendlich, ja,
wenn die Knoten unterschiedlich sind, ist unendlich,
weil ich muss eine Kante lang laufen,
wenn ich quasi hier mich von I nach J
auch bewege
Was ist LEJ oben 1? LEJ oben 1 bedeutet,
die Länge des kürzesten Falles von VI nach VJ mit maximal einer Kante.
Das ist nichts weiter als unsere Gewichtsmatrix, weil wenn wir,
wenn wir nochmal gucken, wie die definiert war,
die stand hier, dann ist, das war ja null,
genau, wenn Ilajot ist und es ist die Kantenlänge,
wenn die beiden durch eine Kante verbunden sind und sonst ist es unendlich.
Das ist genau die Länge des kürzesten Pfades,
die ja, wenn wir die Beschränkung haben,
dass wir maximal
eine Kante verwenden dürfen
So, was können wir jetzt tun, wenn wir m
viele Kanten verwenden dürfen? Ja, wir haben wieder zwei Knoten.
Ah, wir haben Knoten i und wir haben Knoten J.
Und wir haben vielleicht schon einen kürzesten Pfad von ihm
nach J, der besteht aus m-minus 1 fielen Kanten.
Ja. Wir maximieren darüber, es könnte sein,
dass das der kürzeste Pfad ist, auch wenn wir M-Kanten benutzen dürfen.
Ja, wir nehmen jetzt erstmal nur die m-1 fielen,
aber kann ja sein, dass ein Pfad der M-Kanten benutzt,
gar nicht Es könnte aber sein, dass es einen gibt,
der M-Kanten benutzt.
Wie sähe der aus? Also wenn es einen gibt,
der M-Kanten benutzt, dann hat der eine Kante,
die führt uns zu irgendeinem Knoten K. Und dann hätten wir natürlich einen kürzesten Pfad zu diesem einen Knoten K.
Und dieser kürzeste Pfad hätte natürlich wieder M-1 viele Kanten.
Ja, und dann wären diese M-1 fielen plus.
Dieser eine wären dann genau die M fielen Kanten. Okay,
und das Einzige, was wir jetzt machen müssen,
ist, wir müssen für K einfach ausprobieren,
alle Knoten,
die wir haben
Es gibt hier vielleicht ganz viele Knoten, die wir ausprobieren können.
Und für jeden dieser Knoten müssen wir überprüfen,
ob dieser Pfad, wenn wir minus eins,
viele Kanten dahin verwenden, oder ich müsste sagen,
kleiner gleich, minus eins, viele Kanten.
Und dann diese eine letzte Kante verwendet, ob der Vater kürzer wird.
Und dann hätten wir berechnet, was das LIJ oben M ist.
LIJ oben M ist also nichts weiter als das Minimum des kürzesten Falls,
wenn wir maximal minus eins viele Kanten verwenden können.
Oder wir nehmen das Minimum über alle Knoten,
also die Knotennummer geht von eins bis N,
die Länge des kürzesten Fahrrades von I bis zu diesem Knoten K,
der Länge M minus 1 plus die Länge der letzten Kante von K nach J.
Das ist ja wie K-J-T. Okay,
das ist eine rekursive Definition von der Länge des kürzesten Fahrrades.
Okay, jetzt können wir diese Gleichung,
können wir überführen in ein Stückchen Pseudo-Code,
das Stückchen Pseudo-Code berechnet uns,
das LM aus einem LM minus
Das macht die Funktion, Extent short is pass.
Die macht also nichts weiter als genau diese Gleichung umzusetzen.
Also wir speichern den N, die Anzahl der Zeilen,
die wir haben. El Strich ist jetzt eine neue Matrix.
Wir müssen ja irgendwie mit dem M,
wir werden jetzt, also nicht mit dem Exponenten machen,
sondern sagen einfach, wir haben eine neue Matrix-L-Strich.
Und es ist also eine neue Nx-N-Matrix,
müsste sie irgendwie initialisieren, müssen sie auch nicht.
Machen wir jetzt gleich sowieso. Dann haben wir jetzt
zwei Vorschleifen, die betrachten alle Knotenpaar,
Ja, wir müssen ja für alle Paare den kürzesten Weg berechnen.
Also IJ wird also durchiteriert, alle möglichen Kombinationen.
Und jetzt berechnen wir genau dieses Minimum hier. Wir setzen
das LIJ-Strich erstmal auf unendlich. Und jetzt betrachten wir alle Knoten
K. K läuft jetzt von 1 bis N, ja.
Und wir setzen dann das LIJ-Strich auf das Minimum von LIJ-Strich,
also das Minimum, was wir bisher schon gefunden haben.
Und LIK plus WKJ. Ja, also die Länge des
kürzesten Fahrtes von I nach K, die wir hier als Eingabe haben.
Das ist, das entspricht hier dem LIJ oben,
M minus 1. Plus das WKJ,
das ist die Kantenlänge von K nach J. Okay,
der Pseudocode berechnet das Gleiche wie dies hier.
Er ist vielleicht, also ist ein bisschen anders aufgeschrieben,
man muss ein bisschen auffassen. Also diese Minimierung hier mit dem LIJ-Strich,
das sieht genauso aus wie hier so ein bisschen,
aber das ist natürlich nicht das Gleiche.
Also dieses Minimum, das ersetzt quasi das Minimieren über diese
ennenviele Schritte. Also weil man hier immer das Minimum,
das bereits berechnete Minimum mit dem neuen Wert vergleicht.
Also dieses Minimum ist das hier. Ja, das sieht so
ein bisschen so aus, als wenn dieses Millimum das wäre.
Das stimmt natürlich nicht. Dieses Minimum ist das Minimum.
Und jetzt fragt man sich, warum wird das LIJ mit unendlich initialisiert?
Eigentlich könnte man das doch mit LIJs oben minus eins.
Das wäre in dieser Nomenkulation, das wäre ja die Eingabe Matrix L. L. IJ.
Das könnte man da auch machen. Wäre auch in Ordnung
. Das muss man nur nicht, weil wir wissen,
dass in dieser Schleife wird ja auch das J prozessiert.
Und dann würde hier L-I-J plus W-J-J stehen. WJJS 0. Das heißt,
in dieser Schleife wird automatisch auch über diesen Fall hier Minimum ja, weil sie,
sie könnten auch sagen, der, dieses LIJ oben,
minus 1, ist das gleiche wie L-I-J oben,
minus 1 plus WJJ, weil WJJ 0 ist.
Und dann ist es automatisch hier in der Summe drin.
Also auch in der Rekurrenzgleichung könnte man das natürlich steingenommen weglassen.
Es ist da ein bisschen schwerer nachzuvollziehen, wie das funktioniert.
Okay, gut, also damit könnten wir tatsächlich vorausgesetzt,
wir haben jetzt ein L-M-1, ein L-M unterrechnen.
Und jetzt machen wir im Prinzip Das Gleiche wie das,
was eigentlich auch beim Bellmann-Fordalgorithmus passiert. Wir gehen einfach über
die Kanten, über die Anzahl der Kanten der kürzesten Pfade. Wir zählen das jetzt einfach hoch. Okay,
so, also L.E.J. OMM gibt die Länge der kürzesten Pfade mit maximal M. Kanten an,
das hatten wir schon, das ist Wiederholung, Fall 1,
der Eingabegraf enthält keine negativen Zyklen, dann wissen wir,
dass der kürzeste Pfad aus maximal N minus 1 fielen Kanten bestehen kann,
weil jeder Knoten nur einmal vorkommen kann, ja,
und dann wissen wir, dass das Delta IJ,
das muss dem LIJ oben N minus eins entsprechen und es wird sich später auch nicht mehr ändern.
Wenn Sie das LEJ nochmal in diese Extent-Funktion stecken,
dann hätten Sie LEJ oben enden und wenn Sie sie nochmal reinschreiben,
kriegen Sie LEJ oben N plus eins, aber kommt über das Gleiche raus.
Auch das ist genauso wie beim Bellmann-Ford-Algorithmus. Wenn wir keine
negativen Zyklen haben, dann hat die erneute Relaxation keinen Gewinn gebracht.
Sie hat die Fahrtlängen nicht weiter verkürzt und alles ist gleich geblieben.
Wenn wir negative Zyklen haben, dann gibt es tatsächlich jetzt einen Eintrag,
L-E-I, der kleiner wird als Null
Ja, das ist dann ein negativer Zyklus.
Und der hat zur Folge, dass wenn wir nun weiterrechnen,
wenn wir auch das LIJ oben N und LIJ oben N plus 1 berechnen,
die Werte nicht mehr, nicht konvergieren.
Die bleiben nicht gleich, die werden immer kleiner,
und zwar an den Stellen, wo wir negative Zyklen haben.
Das heißt, wir können mit genau den gleichen Trick wie beim
Bellmann Ford erkennen, ob der Graf negative Zyklen hat.
Und wir können theoretisch sogar sagen, wo die auftreten.
Okay, so, wie können wir jetzt die kürzesten Pfade
mit Extent Short of Path berechnen?
Naja, wir machen das einfach
N minus ein Mal. Wir wiederholen das einfach immer wieder. Okay,
N ist also die Anzahl der Teil oder die Anzahl
der Knoten in dem Grafen, wenn sie so wollen.
Die erste Iteration können wir uns schenken. Das ist nämlich
genau unsere Gewichtsmatrix W. L. Open 1 ist W. Dann führen
wir die zweite bis zur N-minus ersten Iteration aus.
Und wir sagen immer, dass das L oben 11 und
M ist Extensort des Pass von L. M. minus 1,W.
Das ist also unsere Erweiterungsfunktion. Wir stecken immer die Matrix
rein, die wir vorher berechnet haben und unsere Gewichtsmatrix
Und am Ende haben wir dann das L oben N
minus eins berechnet und das geben wir zurück.
Mit diesem Trick hier können sie auch ganz schnell prüfen,
ob das Ergebnis korrekt ist. Dazu müssten sie einfach nur
Extent Shorts des Pass ein weiteres Mal aufrufen und alle Werte vergleichen,
ob sich noch irgendwas verändert hat.
Habe ich jetzt hier nicht gemacht. Okay, dieser Algorithmus
wäre also ein All-Pass-Shorts-Pass-Algorithmus, der korrekt kürzeste Pfade berechnet.
Und er hat schon den suggestiven namens Slow All Pass Shorts des Pass,
weil wir wissen,
dass Extent Shorts des Path dauert einen Laufzeitbedarf von Endhof 3. Also eine,
zwei, drei ineinander geschachtelte Schleifen, die laufen jeweils von 1 bis N,
macht also einen Laufzeitbedarf von N-Hoch 3 für das Extended Short is Paths.
Und dann müssen wir das Ganze jetzt in dieser Schleife noch
en mal machen, kommen wir auf N-Hoch 4. Okay,
also das Verfahren hat eine Laufzeit von N-Hoch 4.
Gucken wir nochmal zurück, wo war unser Deixtra? Der war,
naja, gehen wir davon aus, wir haben dichten Grafen,
dann hätten wir en mal M mal Login.
Das M, das wäre im ungünstigsten Fall ein Quadrat,
wenn jeder Knot mit jedem anderen verbunden wäre,
dann hätten wir hier N hoch 3 Login.
Also selbst im ungünstigsten Fall ist der Deixtra-Algorithmus in einfacher Anwendung noch besser.
Aber unser Algorithmus kann ja mit negativen Kantendenken umgehen.
Das konnte der extra nicht. Das heißt,
eigentlich müssen wir es eher mit dem Bellmann-Ford-Algorithmus vergleichen.
Und da kommen wir auf Endquadrat mal M.
Und wenn wir jetzt von einem dichten Grafen ausgehen,
also einen, der so,
wo jeder Knoten im Mittel mit ganz vielen anderen verbunden ist,
dann ist das M auch wieder in der Größenordnung ein Quadrat.
Und dann hätte der N die N malige Ausführung des Bellmann-Ford-Algorithmus
auch die Laufzeit N.O.4.
Also dieser Slow
All Pass short is Pass-Problem, ist zumindest in dem einen Szenario,
wir haben einen dichten Graf mit negativen Kantenbängen,
nicht langsamer als das Beste, was wir jetzt kennen.
Immerhin, ja, wir haben einen Fall gefunden und wir stehen ja noch am Anfang,
ja, der heißt ja nicht umsonst Slow.
Das heißt, vielleicht gibt es ja Optionen,
den auch zu beschleunigen, ja. Um die zu finden,
muss man mal einen Schritt zurücktreten und diesen Algorithmus mal anschauen.
Und manchmal hilft es ungemein,
wenn man so ein bisschen in so einen Pattern an Recognition,
also so ein Mustererkennungsmodus von Text geht, ja.
Wenn sie diesen Algorithmus sehen und sich viel mit Algorithmen beschäftigt haben,
dann sollte ihnen sofort eine Analogie ins Auge springen, ja.
Und zwar, dieser Algorithmus ist nahezu identisch, mit dem Algorithmus,
den wir verwenden, um Atritzen zu multiplizieren, ja.
Matrix Multiplikationen haben sie wahrscheinlich alle schon längst verdrängt,
aus ihrem Hirn, wenn sie Matritzen multiplizieren, dann geht das so,
dass sie Dass sie für jeden Eintrag in dieser Ergebnismatrix so vorgehen,
wenn sie den Eintrag IJ haben,
dass sie die IT-Zeile der ersten Matrix A nehmen und sie multiplizieren,
dass Komponentenweise mit der jten Spalte der Matrix B,
also das, mal das, bloß das, mal das,
bloß das, mal das und so weiter,
bis sie da durch sind.
Und das ergibt dir gerade den Eintrag IJs in der Ergebnismatrix.
Das ist die Art und Weise, wie wir Matritzen multiplizieren.
So, hier steht der Algorithmus für Extent Short is Pars.
Hier steht der Algorithmus für die Matrix-Multiplikation. Wir bestimmen die
Anzahl der Zeilen, in denen der Matrix hier ist,
dem Matrix hier die Matrix A. Wir brauchen eine Ergebnismatrix.
Hier ist es L-Strich. Hier ist die Matrix C. Dann
haben wir zwei Vorschleifen. Die sind einfach dafür da,
dass wir in der Ergebnismatrix alle Einträge hier der Reihe nach berechnen.
Um seinen Eintrag zu berechnen, setzen wir hier den Wert auf unendlich
und gehen dann hier diesen K-Wert von 1 bis N durch.
Das ist hier das K, was hier so durchläuft in
dieser Richtung und beziehungsweise hier runter. Und dann rechnen wir
im Einfall industrialisieren wir mit unendlich, in dem anderen mit Null.
In dem einen Fall nehmen wir das Minimum von dem,
was wir vorher hatten und L-I-K plus WKJ und dem anderen,
initialisieren wir mit null und addieren zu dem C-I-J, das A-I-K mal B-K-J.
Ja, und dann geben wir die Matex zurück.
So, das ist nahezu identisch und das Einzige,
was wir machen, ist ein paar Austauschoperationen. Ja,
die Matrix L wird zur Matrix A, ist geschenkt, ja,
ist nur umbenannt, die Matrix W wird zur Matrix W,
die Matrix L-Strich zur Matrix C, ist alles geschenkt,
sind nur andere variablen Namen.
Das unendlich hier, das wird zur Null, ja,
das Minimum, dieses Minimumsberechnung,
die verknüpft quasi den Wert, den wir vorher hatten,
mit dem, den wir in dieser Iteration berechnen,
das wird zu Plus
Also das Minimum wird zu Plus. Und das Plus hier,
das ist die Verknüpfung der Werte der beiden Matrizen, dass wir zumal, ja,
also das ist die Überführung quasi, die wir durchführen.
Okay, das heißt, Extensort des Pars ist eine Matrix-Multiplikation, allerdings mit anderen Operationen.
Wir verwenden MIN und Plus, statt Plus und Mal.
Und das neutrale Element bezüglich der Minimumsbildung ist unendlich.
Genauso wie die Null, das neutrale Element der Addition ist,
wenn sie null auf irgendetwas drauf addieren,
dann kommt da der Wert drauf.
Also null plus X ist immer X. Ja,
genauso ist das Minimum von unendlich und X immer
X. Neutrales Element.
Also insofern passt das tatsächlich hervorragend zusammen
Jetzt sagen wir einfach, Extensort des Pass ist nichts weiter als eine Matrix-Operation.
Die nennen wir jetzt Kreuzchen mit Kringel, irgendwie so.
Also wir denken, es ist ein tolles neues Symbol aus
und sagen, das ist jetzt unsere Matrix-Multiplikation hier.
Und weil diese Operation so symmetrisch ist,
können wir ganz schnell zeigen, dass genau wie bei der Matrix-Multiplikation,
auch für Extensort des Pass, das Assoziativgesetz gilt.
Also wenn wir diese Operation mehrfach ausführen,
dann können wir die Klammern beliebig setzen. Also A,
Ah, ich sag jetzt mal Kreuzchen, ja,
da haben wir sie A-Kreuz und dann B-Kreuz C,
ja, ist das Gleiche wie A-Kreuz B-Kreuz C.
Das können Sie nachweisen, das Assoziativgesetz auch gilt,
wenn Sie hier die Operation entsprechend austauschen.
Und ja, jetzt stellt sich sofort die Frage,
okay, wir gucken uns mal unseren Slow-Algorithmus an.
Was macht er eigentlich? Ja? Was macht,
der macht eigentlich nichts anderes als der multipliziert immer nur weh miteinander.
Der rechnet weh, mal weh und dann wieder mal weh.
Ja, was anderes tut er gar nicht,
Also der Slow-Algorithmus berechnet weh und dann mal weh,
mal weh und so weiter. Und das Einzige,
was wir zahlen, was wir machen, das machen wir,
das machen wir genau endminus eins mal hier.
Naja, in minus zwei, aber multiplizieren wir das miteinander.
Jetzt haben wir es gerade schon gesehen, die Reihenfolge,
in der wir diese Operationen ausführen, ist eigentlich völlig egal. Wir können,
wir machen das jetzt so, wir rechnen erst weh,
Kreuz weh, dann haben wir ein Ergebnis,
das Ergebnis von dem hier war hier das L,
das SL oben zwei und dann rechnen wir das wieder mit
dem zusammen und dann kriegen wir das L um 3. Und dann machen wir das so weiter.
Müssen wir gar nicht so machen. Ist das Assoziativgesetzgeld?
Wir dürfen Belier. Wir könnten auch hier hinten anfangen. Komm,
wir müssen das gleiche, aber könnten wir auch machen,
ne? Aber wir könnten zum Beispiel auch Folgendes machen.
Wir könnten zum Beispiel sagen, warum machen wir nicht das so?
Wir rechnen mal weh, mal weh.
Dann kriegen wir hier sowas wie W hoch 2, ja?
Und dann können wir hier nochmal weh, mal weh rechnen.
Wäre ja auch, W hoch 2. Dann könnten wir die
beiden miteinander multiplizieren und dann hätten wir hier sowas wie W
Und auf die Art und Weise könnten wir ja vielleicht viel schneller unser W-Hoch-N ausrechnen.
Und genau das ist der Trick, ja.
Ich zeige Ihnen, das Beispiel zeichne ich Ihnen gleich.
Genau, das ist der Trick, was wir machen.
Wir wissen, diese Operation hier, die ist assoziativ,
die Reihenfolge ist egal.
Wir haben rausgefunden, wir müssen nicht genau wehhoch-n-minus-eins berechnen.
Wir können irgendeinen Wehhoch-K berechnen, wo das K größer ist als N-minus-eins.
Ist völlig egal, ja. Weil wir wissen,
die Werte bleiben konstant, vorausgesetzt,
wir haben keine negativen Zyklen
Das heißt, wir berechnen K, als der Logarithmus zur Basis 2 von N minus 1,
und dann berechnen wir einfach W hoch K,
und das machen wir, indem wir immer wieder exponentieren.
Okay, also wir berechnen die Folge W-W-Quadrat, W hoch W-W hoch 8,
und irgendwann sind wir dann bei einem W hoch,
irgendwas angekommen, was größer ist als N minus 1.
Das wäre ein Faster-All-Pairs-Short des Pass-Algorithmus,
der macht also nichts, das sieht noch genauso aus,
nur die Schleife sieht jetzt anders aus,
wir haben hier eine Wild-Schleife, die läuft so lange,
wie das M kleiner ist als N minus 1,
wir berechnen L hoch 2M, Durch ein Extent-Short des Fahrts,
von LM und multiplizieren LM mit LM.
Dafür war die Funktion eigentlich gar nicht da, aber es ist egal.
Wir haben gezeigt, sie ist assoziativ, wir dürfen das beliebig miteinander verknüpfen.
Wir berechnen einfach, wir quadrieren quasi hier diese Matrix.
Wenn Sie jetzt versuchen zu verstehen, also eben haben Sie
wahrscheinlich noch gut verstanden, was diese Extent-Funktion macht,
die habe ich Ihnen ja erklärt anhand des Verfahrens.
Das nachzuvollziehen ist jetzt irgendwie schwierig, aber es ist auch
nicht mehr wichtig. Wir wissen nur,
es kommt das richtige Ergebnis raus und wir wissen,
wir haben M, hier können MB2 multiplizieren,
haben also das um zwei vergrößerte M ausgerechnet.
Und das machen wir jetzt einfach hier immer
So weiter. Und das müssen wir genau Log-in mal machen.
Logrhythmus zur Basis 2N mal. Okay,
unser Algorithmus hat die Laufzeit N hoch 3 Log-in.
Ja? Durch diesen Trick und wenn wir mal wieder vergleichen.
Der Deixtra auf einen dichten Grafen hatte N hoch 3 Log-in-Laufzeit.
Ja, das heißt, wir haben zumindest für den
dichten Grafen die Laufzeit des Deixtra erreicht.
Der Bellmann Ford mit negativen Kantengelichten hatte N hoch 4. Das heißt,
wenn wir einen dichten Grafen mit negativen Kantengewichten haben,
das war der ungünstigste Fall, Dann haben wir ihn jetzt geschlagen.
Ja, jetzt haben wir Endhof 3 Login. Okay,
gut, soweit so gut. Und wenn man jetzt schon
eine Analogie zur Matrix-Multiplikation hat, stellt sich natürlich sofort die Frage,
kann man nicht vielleicht auch die Matrix-Multiplikation beschleunigen?
Und das scheint zumindest nicht der Fall zu sein,
dass man dieses hier verschleunigen kann.
Es gehört wohl auch zu einem der erstaunlichsten Resultate der Informatik,
dass das geht, aber das geht.
Ja, also man kann, Madrid ist schneller,
multiplizieren als N hoch 3 Zeit.
Das werden wir auch noch sehen, aber auch ein bisschen später
Der nächsten Vorlesung uns noch mal einen ganzen Schritt zurückgehen und noch mal einen anderen Weg finden,
um kürzeste Wege zwischen allen Knoten zu berechnen. So,
das war's für heute und bevor Sie weglaufen,
hier schon mal die Ankündigung,
die Vorlesung am nächsten Montag fällt leider aus,
weil ich nicht da bin und meine Übungsgruppenleiter so viel mit den Übungen beschäftigt sind,
dass Sie gesagt haben, oh nein, bitte nicht.
Also es macht auch nichts,
also wir machen hier weiter dann nächste Woche Mittwoch,
wir werden das auch noch mal über Stine ankündigen.