Wie komme ich am günstigsten von links nach rechts?
Kürzeste Wege und günstigste Wege
In vielen Anwendungen kann es nützlich sein, den kürzesten Weg von a nach b zu berechnen.
Dabei muss die Länge eines Weges nicht unbedingt die Länge in Metern sein: Genauso gut kann man die Kosten eines Weges betrachten – man sucht also den günstigsten Weg.
Hier wird der Bellman-Ford-Algorithmus vorgestellt, der günstigste Wege auch bei negativen Kosten berechnet.
Wie komme ich am günstigsten von links nach rechts?
Kürzeste Wege
In vielen Anwendungen kann es nützlich sein, den kürzesten Weg von a nach b zu berechnen.
Dabei muss die Länge eines Weges nicht unbedingt die Länge in Metern sein: Genauso gut kann man die Fahrzeit eines Weges betrachten oder, ob wir für dessen Benutzung Geld zahlen müssen – oder Geld erhalten.
Im Allgemeinen sprechen wir von Kosten.
Dementsprechend weist man jedem Teilstück des Weges – auch "Kante" genannt – Kosten zu.
Der Algorithmus von Dijkstra berechnet kürzeste – oder eben kostengünstigste Wege, wenn alle Kosten positive Zahlen sind.
Wenn man allerdings auch negative Zahlen zulässt, scheitert der Algorithmus.
Der Bellman-Ford-Algorithmus dagegen kann auch mit negativen Kosten arbeiten.
Diese können beispielsweise für einen Taxifahrer entstehen, wenn er einen Fahrgast transportiert und für die Fahrt mehr Geld einnimmt, als ihn Benzin und Fahrzeug für die Fahrt kosten. Fährt er ohne Fahrgast, sind seine Kosten positiv.
Idee des Algorithmus
Die Kante ist eine Abkürzung: Wir wissen, dass es uns 20 kostet, um vom Startknoten zum linken Knoten zu gelangen. Der Weg vom linken zum rechten Knoten kostet 1. Also kommt man vom Startknoten zum rechten Knoten mit Kosten 21.
Der Bellman-Ford-Algorithmus berechnet die Kosten der günstigsten Wege von einem Startknoten aus zu allen anderen Knoten im Graph. Er kann dadurch die günstigsten Wege selbst konstruieren.
Der Algorithmus geht dabei iterativ vor, er geht also zunächst von einer sehr schlechten Schätzung der Kosten aus, und verbessert diese so lange, bis die korrekten Werte gefunden sind.
Die erste Schätzung ist:
Der Startknoten hat Kosten 0, denn seine Entfernung zu sich selbst ist natürlich 0.
Alle anderen Knoten haben Kosten unendlich, also die schlechtestmögliche Schätzung.
Danach prüft er alle Kanten auf folgende Bedingung: Sind die Kosten des Anfangsknotens der Kante plus die Kosten für die Benutzung der Kante niedriger als die Kosten des Zielknotens der Kante?
Falls dies der Fall ist, so haben wir eine Abkürzung gefunden: Es ist besser, die eben geprüfte Kante zu nutzen, als den bisherigen Weg.
Deshalb werden die Kosten des Zielknotens der Kante aktualisiert: Sie entsprechen jetzt genau den Kosten des Anfangsknotens der Kante plus den Kosten für die Benutzung der Kante (siehe Beispiel rechts).
Alle Kanten des Graphen zu betrachten und die Kosten der Knoten zu aktualisieren, nennen wir Phase. Leider reicht es nicht aus, alle Kanten nur einmal zu betrachten.
Nach der ersten Phase haben wir die Kosten für alle Knoten korrekt berechnet, für die der günstigste Weg nur eine Kante benutzt. Nach 2 Phasen haben wir schon die Wege,
die maximal 2 Kanten benutzen, korrekt berechnet und so weiter.
Der grüne Weg vom Startknoten ist der günstigste Weg. Er benutzt 3 Kanten.
Wie viele Phasen brauchen wir also? Hier hilft uns die Beobachtung, dass ein kürzester Weg weniger Kanten benutzen muss, als es Knoten im Graph gibt.
Wir brauchen also eine Phase weniger, als es Knoten im Graph gibt. Ein kürzester Weg, der mehr Kanten benutzte, als es Knoten gibt, würde einen Knoten zweimal besuchen und somit im Kreis laufen.
Konstruktion des günstigsten Weges
Bei jeder Aktualisierung der Kosten speichert der Algorithmus die Kante, mit deren Hilfe er aktualisiert wurde, als Vorgängerkante des Knotens.
Am Ende des Algorithmus kann dann der günstigste Weg für jeden Knoten konstruiert werden, indem man so lange über Vorgängerkanten läuft, bis man am Startknoten angekommen ist.
Kreise mit negativem Gewicht
Hier müsste ein günstigster Weg unendlich oft im Kreis laufen. Der Weg würde bei jedem Durchlauf kürzer werden.
Falls im Graph ein Kreis existiert, bei dem die Summe der Kantengewichte negativ ist – ein negativer Kreis, wird der Algorithmus möglicherweise keinen günstigsten Weg finden.
Wie man an dem Beispiel rechts schon sehen kann, sind Wege in diesem Fall nämlich möglicherweise unendlich günstig – man läuft einfach immer weiter durch den Kreis.
Dieses Problem tritt auf, falls der negative Kreis vom Startknoten aus erreichbar ist.
Erfreulicherweise kann der Algorithmus aber entdecken, ob ein solcher negativer Kreis existiert.
Dies wird im letzten Teil des Algorithmus überprüft.
Ein erreichbarer negativer Kreis existiert genau dann, wenn nach dem Durchlaufen aller Phasen immer noch Abkürzungen möglich sind.
Der Algorithmus überprüft also am Ende nochmals bei allen Kanten, ob die Kosten des Anfangsknotens der Kante plus die Kosten für die Benutzung der Kante niedriger sind als die Kosten des Zielknotens der Kante.
Falls dies bei einer Kante der Fall ist, so wird die Meldung "negativer Kreis gefunden" ausgegeben.
Mithilfe der Vorgängerkanten kann man den negativen Kreis sogar finden: Man läuft so lange zurück, bis man im Kreis gelaufen ist (und das Gewicht des Kreises negativ ist).
Was nun?
Einen Graph erstellen und den Algorithmus durchspielen
Startknoten, von dem aus die Entfernungen und günstigsten Wege berechnet werden.
Kante, die bereits ausgewählt wurde.
Kante, die im letzten Schritt ausgewählt wurde.
Legende
Wie ist die optimale Sortierung der Kanten?
Wie ist die optimale Sortierung der Kanten?
Der Bellman-Ford-Algorithmus kann schon nach einer einzigen Phase alle Entfernungen korrekt berechnet haben.
Dafür müssen die Kanten allerdings in der optimalen Reihenfolge betrachtet werden.
Diese Reihenfolge ist aber nicht leicht zu finden – das dauert genauso lange wie der Bellman-Ford-Algorithmus selbst.
Im Beispiel sieht man: Links ist die Reihenfolge sinnvoll, der Algorithmus kann schon nach einer Runde alle Kosten korrekt berechnet haben. Rechts ist das nicht der Fall.
In dieser Aufgabe kannst du experimentieren, wie viele Phasen der Bellman-Ford-Algorithmus bei verschiedenen Sortierungen benötigt.
Beim Wechsel des Tabs wird die Aufgabe abgebrochen.
Eingabe: Gewichteter, ungerichteter Graph G=(V,E) mit Gewichtsfunktion l.
Ausgabe: Eine Liste {d(v[j]) : j = 1,..,n}, die die Distanzen dist(v[1],v[j]) = d(v[j]) enthält,
falls von v[1] aus keine Kreise negativer Länge erreichbar sind.
Die Meldung "Kreis negativer Länge", falls von v[1] ein solcher Kreis erreichbar ist.
BEGIN
d(v[1]) ← 0
FOR j = 2,..,n DO
d(v[j]) ← ∞
FOR i = 1,..,(|V|-1) DO
FOR ALL (u,v) aus E DO
d(v) ← min(d(v), d(u) + l(u,v))
FOR ALL (u,v) aus E DO
IF d(v) > d(u) + l(u,v) DO
Meldung: "Kreis negativer Länge"
END
Wie schnell ist der Algorithmus?
Geschwindigkeit von Algorithmen
Die Geschwindigkeit von Algorithmen wird üblicherweise in der Anzahl an Einzelschritten gemessen, die der Algorithmus bei der Ausführung benötigt.
Einzelschritte sind beispielsweise:
Zuweisungen – Weise Knoten 1 den Wert 20 zu.
Vergleiche – Ist 20 größer als 23?
Vergleich und Zuweisung – Falls 20 größer als 15 ist, setze Variable n auf 20.
Einfache Arithmetische Operationen – Was ist 5 + 5 ?
Da es sehr schwierig sein kann, diese Einzelschritte exakt zu zählen, möchte man nur die ungefähre Größenordnung der Anzahl Schritte wissen.
Man spricht auch von der Laufzeit des Algorithmus.
Meistens ist es besonders interessant, zu wissen, wie die Geschwindigkeit des Algorithmus von der Größe der Eingabe (hier: Anzahl Kanten und Knoten im Graph) abhängt.
Laufzeit des Bellman-Ford-Algorithmus
Nehmen wir an, dass der Bellman-Ford-Algorithmus auf einem Graph mit n Knoten und m Kanten ausgeführt wird.
Am Anfang wird jedem Knoten der Wert ∞ zugewiesen. Dafür benötigen wir n Einzelschritte.
Danach kommen die n-1 Phasen des Algorithmus – eine Phase weniger als es Knoten gibt.
In jeder Phase wird jede Kante des Graphen überprüft, und möglicherweise wird der Abstandswert ihres Zielknotens verändert.
Wir können diese Überprüfung und Zuweisung als einen Schritt sehen und haben also in jeder Phase m Einzelschritte.
Insgesamt benötigen die Phasen also m · (n-1) Einzelschritte.
Schließlich überprüft der Algorithmus noch, ob es negative Kreise gibt. Dafür betrachtet er jede Kante einmal.
Insgesamt braucht er für die Überprüfung also m Einzelschritte.
Die Gesamtlaufzeit des Algorithmus ist von der Größenordnung m · n Schritte, weil die n Schritte zu Beginn und die m
Schritt am Schluss des Algorithmus vernachlässigbar gegenüber m · (n-1) sind.
Wie beweist man, dass der Algorithmus stets ein korrektes Ergebnis berechnet?
Ein mathematischer Beweis
In diesem Abschnitt werden wir beweisen, dass der Bellman-Ford-Algorithmus immer ein korrektes Ergebnis liefert, falls der Graph keine vom Startknoten erreichbaren negativen Kreise hat.
Das Prinzip der Induktion
Der Beweis basiert auf dem Prinzip der Induktion. Wir beweisen zunächst, dass wir zu Beginn der ersten Phase bereits die Kosten für
mindestens einen Knoten korrekt berechnet haben. Wir zeigen dann, dass wir in jeder Phase die bisherigen Schätzungen verbessern.
Am Ende jeder Phase kennen wir also für mehr Knoten die korrekten Kosten als zu Beginn der Phase. Außerdem zerstören wir in der jeweiligen Phase keine
Informationen – die Schätzungen können nur besser werden.
Schließlich zeigen wir, dass uns weniger Phasen reichen, als es Knoten gibt, um für alle Knoten die korrekten Kosten zu berechnen.
Nach Phase i gilt:
Der Algorithmus hat jedem Knoten u als Kostenschätzung höchstens die Länge des kürzesten Weges vom Startknoten zu u, der maximal i
Kanten benutzt, zugewiesen, falls ein solcher Weg existiert.
Betrachten wir diese Aussage in ihren Einzelteilen für einen Knoten u am Ende von Phase i:
Falls kein Weg vom Startknoten zu u existiert, der maximal i Kanten benutzt, so erfahren wir nichts.
Falls ein Weg vom Startknoten zu u existiert, der maximal i Kanten benutzt, dann wissen wir, dass die Kostenschätzung für u
höchstens so hoch ist wie die Kosten des Weges. Der Grund ist folgender: Wenn wir den Weg ohne seine letzte Kante betrachten, so sehen wir einen Weg, der i-1 Kanten benutzt.
Die Kosten des letzten Knotens dieses Weges hatten wir also schon zu Beginn der Phase korrekt berechnet. Innerhalb der Phase haben wir alle Kanten, also auch das letzte Teilstück, betrachtet.
Da wir beim Betrachten des letzten Teilstücks die Kosten korrekt aktualisiert haben, sind jetzt auch die Kosten für den letzten Knoten des Gesamtwegs, der i Kanten benutzt, korrekt.
Es reichen weniger Phasen, als es Knoten gibt.
Ein Weg, der mindestens so viele Kanten benutzt, wie es Knoten gibt, kann kein kürzester Weg sein, falls alle Kreise positives Gesamtgewicht haben. Mit jeder Kante, die ein Weg benutzt, sieht er nämlich einen weiteren Knoten (den Zielknoten der Kante).
Dazu kommt noch der Startknoten, den er auch sieht, ohne Kanten benutzt zu haben. Falls er also so viele Kanten benutzt, wie es Knoten gibt, so hat er mindestens einen Knoten zweimal gesehen, ist also im Kreis gelaufen.
Da wir angenommen haben, dass alle Kreise positives Gesamtgewicht haben, wäre es kürzer gewesen, nicht im Kreis zu laufen.
Falls es Kreise mit Gesamtgewicht 0 gibt, so ist es schlicht genauso teuer, diese zu durchlaufen, wie sie auszulassen.
Auch in diesem Fall reichen also die Wege, die weniger Kanten benutzen, als es Knoten gibt.
Wo finde ich noch mehr Informationen zu Graphalgorithmen?
Ein letzter Hinweis zum Ziel und Inhalt dieser Seite und zu Zitationen
Der Lehrstuhl M9 der TU München beschäftigt sich mit diskreter Mathematik, angewandter Geometrie und der mathematischen Optimierung von angewandten Problemen. Die hier dargestellten Algorithmen sind sehr grundlegende Beispiele für Verfahren der diskreten Mathematik (die tägliche Forschung des Lehrstuhls geht weit darüber hinaus). Die vorliegenden Seiten sollen SchülerInnen und Studierenden dabei helfen, diese auch im realen Leben sehr wichtigen Verfahren (besser) zu verstehen und durch Ausprobieren zu durchdringen. Aus diesem Grund konzentriert sich die Darstellung bewusst auf die Ideen der Algorithmen, und präsentiert diese oftmals unter weitestgehendem Verzicht auf mathematische Notation.
Bitte beachten Sie, dass diese Seiten im Rahmen von studentischen Arbeiten unter Betreuung des Lehrstuhls M9 erstellt wurden. Den dabei entstandenen Code und die zugehörige Darstellung können wir nur punktuell überprüfen, und können deshalb keine Garantie für die vollständige Korrektheit der Seiten und der implementierten Algorithmen übernehmen.
Selbstverständlich freuen wir uns über jegliches (auch kritisches) Feedback bezüglich der Anwendungen sowie eventuellen Ungenauigkeiten und Fehlern der Darstellung und der Algorithmen. Bitte nutzen Sie hierzu den Anregungen-Link, welcher auch rechts in der Fußleiste zu finden ist.
Um diese Seite zu zitieren, nutze bitte die folgenden Angaben:
Titel: Der Bellman-Ford - Algorithmus
Autoren: Melanie Herzog, Wolfgang F. Riedl, Richard Stotz; Technische Universität München