Kürzeste-Wege-Algorithmen - Zentrum für Angewandte Informatik

Werbung
Kürzeste-Wege-Algorithmen
Institut für Informatik
Universität zu Köln
19. August 2003
Inhaltsverzeichnis
0.1
Dijkstra-Algorithmus . . . . . . . . . . . . . . . . . . . . . . . . .
0.1.1 Dijkstra in Pidgin-Pascal . . . . . . . . . . . . . . . . . . .
2
3
0.2
Datenstrukturen und Laufzeiten . . . . . . . . . . . . . . . . . . . .
4
0.2.1
0.2.2
(a,b)-Bäume . . . . . . . . . . . . . . . . . . . . . . . . . .
Fibonacci-Heaps . . . . . . . . . . . . . . . . . . . . . . . .
5
6
0.2.3
0.2.4
Buckets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Redistributive Heaps . . . . . . . . . . . . . . . . . . . . . 15
0.3
0.4
Skalierungs-Verfahren . . . . . . . . . . . . . . . . . . . . . . . . . 18
D’Esopo-Pape-Algorithmus . . . . . . . . . . . . . . . . . . . . . . 18
0.5
0.4.1 D’Esopo-Pape-Verfahren . . . . . . . . . . . . . . . . . . . 19
2-Listen-Verfahren und Threshold-Verfahren . . . . . . . . . . . . . 19
0.5.1
0.5.2
0.6
0.7
2-Listen-Verfahren . . . . . . . . . . . . . . . . . . . . . . . 20
Threshold-Algorithmus . . . . . . . . . . . . . . . . . . . . 20
Future-Cost-Verfahren . . . . . . . . . . . . . . . . . . . . . . . . . 21
LP-Formulierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1
2
INHALTSVERZEICHNIS
Kürzeste-Wege-Algorithmen
Gegeben sei ein gerichteter Graph G = (V, E) mit Knotenmenge V und Kantenmenge E und Entfernungen c(v, w) ≥ 0 für (v, w) ∈ E. Zusätzlich sei ein
Knoten s ∈ V ausgezeichnet.
10 ea
QQ
3
Q 9
Q
Q
Q
s
Q?e t
*
2
s eH
H
HH
Hj
H
? 7
14
e
b
Definition 1. Ein Weg P von v ∈ V nach w ∈ V ist eine Folge v 0 , v1 , . . . , vk
von Knoten, so daß v0 = v, vk = wPund (vi , vi+1 ) ∈ E für c(vi , vi+1 )0 ≤ i ≤ k − 1.
k−1
Der Weg hat die Länge c(P ) := i=0
.
Gesucht: Kürzeste Wege von s zu allen anderen Knoten.
Idee des Verfahrens: Wir vergrößern schrittweise eine Menge M von Knoten,
für deren Elemente v ∈ M wir bereits einen kürzesten Weg von s nach v gefunden
haben.
- allen anderen Knoten v ∈
/ M ordnen wir die Länge des bisher gefundenen kürzesten
Weges zu.
0.1
Dijkstra-Algorithmus
Wir bezeichnen mitDist(v) die Länge des (bisher gefundenen) kürzesten Weges
und mit V or(v) den Vorgänger auf einem solchen Weg.
Setze Dist(s) := 0, M := {s}
Für v ∈ V mit (s, v) ∈ E setze Dist(v) := c(s, v) und V or(v) := s
Für v ∈ V mit (s, v) ∈
/ E setze Dist(v) := +∞ und V or(v) := ∅
Bestimme u ∈
/ M mit Dist(u) = min{Dist(v) : v ∈
/ M }.
Falls Dist(u) = ∞, dann ST OP. Andernfalls setze M = M ∪ {u}.
Für alle v ∈
/ M mit (u, v) ∈ E
Falls Dist(v) > Dist(u) + c(u, v) dann setze:
Dist(v) = Dist(u) + c(u, v)
V or(v) = u
Falls M 6= V, dann gehe zu 2, sonst STOP.
INHALTSVERZEICHNIS
3
Satz 2. Der Dijkstra-Algorithmus berechnet kürzeste Wege von s zu allen anderen erreichbaren Knoten.
Beweis: Wir zeigen per Induktion über k = 1, . . . , |M |:
(i) v ∈ M ⇒ Dist(v) ist Distanz des kürzesten (s, v)-Weges
(ii) v ∈
/ M ⇒ Dist(v) ist Distanz des kürzesten (s, v)-Weges, der (außer v)
nur Knoten aus M benutzt.
Ist k = 1 (d.h. nur s ∈ M ), so sind die Aussagen korrekt. Seien die Aussagen also
für k bewiesen und sei u der neu in M aufgenommene Knoten. Falls Dist(u) = ∞,
so ist nichts mehr zu zeigen. Andernfalls:
(i) Die Aussage gilt nach Induktionsannahme bereits für alle Knoten v ∈ M, v 6=
u. Per Induktion ist Dist(u) die Länge eines kürzesten Weges von s nach u, der
als innere Knoten nur Knoten aus M benutzen darf. Angenommen es existiert ein
kürzerer Weg P von s nach u. P muß dann einen ersten Knoten w ∈
/ M enthalten:
s → · → · · · · → w → · → · · · → u. Sei P 0 der Anfang von P bis w. P 0 enthält im
Inneren nur Knoten aus M. Per Induktion ist Dist(w) ≤ c(P 0 ). Nach Wahl von u
gilt Dist(u) ≤ Dist(w). Somit Dist(u) ≤ Dist(w) ≤ c(P 0 ) ≤ c(P ) < Dist(u).
Widerspruch.
(ii) Nach Schritt 4 ist für v ∈
/ M, Dist(v) die Länge des kürzesten Weges von
s nach v, der nur innere Knoten aus M benutzt und der entweder u nicht oder als
vorletzten Knoten benutzt.
Angenommen es existiert ein kürzerer Weg P von s nach v über Knoten in M.
Sei w der vorletzte Knoten in P. Dann ist w 6= u. Sei P 0 der in P enthaltene (s, w)Weg. Da w früher als u in M aufgenommen wurde, ist Dist(w) die Länge eines
kürzesten (s, w)-Weges P 00 , der nur Knoten aus M \{u} benutzt. Somit Dist(v) >
c(P ) ≥ c(P 0 ) + c(w, v) ≥ c(P 00 ) + c(w, v) ≥ Dist(v), da P 00 ∪ {(w, v)} ein (s, v)Weg über Knoten aus M \{u} ist. Widerspruch.
2
Korollar 3. (aus dem Beweis): Ist man nur an dem kürzesten Weg von s nach
t interessiert, so genügt es, den Algorithmus zu stoppen, sobald t ∈ M.
2
0.1.1
Dijkstra in Pidgin-Pascal
Knoten, die in die Menge M aufgenommen worden sind, heißen markiert. Für die
Implementation des Dijkstra-Algorithmus ist es besser, an Stelle der Menge M die
Menge U := {v ∈ V : Dist(v) < ∞, v ∈
/ M } zu betrachten. Diese Menge, die aus
den noch nicht markierten Knoten besteht, zu denen der Algorithmus schon einen
provisorischen Weg gefunden hat, heißt Front. Neu formuliert heißt der Algorithmus
jetzt so:
Dist(s) := 0, U = ∅
for v ∈ V mit (s, v) ∈ E do
Dist(v) = c(s, v), V or(v) = s
U = U ∪ {v}
endfor
INHALTSVERZEICHNIS
4
while U 6= ∅
wähle u ∈ U mit Dist(u) minimal in U (finde Min)
lösche u aus U (lösche Min)
for all (u, v) ∈ E
if Dist(u) + c(u, v) < Dist(v) then
Dist(v) = Dist(u) + c(u, v), V or(v) = u. (verringere)
if v ∈
/ U then füge v zu U hinzu. (füge ein)
endif
endfor
endwhile
Abschätzung der Laufzeit
Lemma 4. Die Laufzeit des Dijkstra-Algorithmus ist
O (n · max{ O(finde Min), O(lösche Min), O(füge ein) }) + m· O(verringere).
Beweis: Die while-Schleife kann höchstens n = |V | mal ausgeführt werden, da
jeder Knoten höchstens einmal als Minimum auftreten kann. Die darin enthaltene
for-Schleife kann aber auch nur einmal für jede Kante durchlaufen werden. Somit:
n Ausführungen von finde Min, lösche Min, füge ein,
m Ausführungen von Verringere.
2
0.2
Datenstrukturen und Laufzeiten
Für die Implementierung des Dijkstra-Algorithmus benötigen wir Datenstrukturen,
um den Graphen, die Distanz (Dist(v)) und den Vorgänger (V or(v)) eines Knotens sowie die Front (Menge U ) effizient zu verwalten. Der Graph kann z.B. in einer
Adjazenzliste abgespeichert werden:
Feld Tail [1, . . . , n]: Tail(i) zeigt auf Beginn einer verketteten Liste, die die Endknoten j und Kosten von Kanten (i, j) ∈ E enthält.
Die Distanz und der Vorgänger eines Knotens können in Felder Dist[1 . . . n],
V or[1 . . . n] abgelegt werden.
Die Verwaltung der Front verlangt eine Datenstruktur, die die folgenden Operationen unterstützt.
• finde Minimum
• lösche Minimum
• füge ein
• verringere Inhalt eines gegebenen Elements.
Hier gibt es viele verschiedene Möglichkeiten. Wir wollen nun einige vorstellen und
zeigen, wie sich ihre Verwendung auf die Laufzeit auswirkt.
5
INHALTSVERZEICHNIS
0.2.1
(a,b)-Bäume
Wir wählen einen ungeordneten (a, 2a)-Baum der wir folgt aufgebaut ist:
1. Die Blätter enthalten die Elemente (Dist(u), u) in beliebiger Reihenfolge
2. Jeder innere Knoten v enthält den minimalen Wert eines Blattes unter v mit
Zeiger auf dieses Blatt.
3. Ein zusätzliches Zeigerfeld Pointer [1, . . . , n], wobei Pointer (u) auf das Blatt
zeigt, das u enthält, bzw. Pointer (u) = ∅, falls u ∈
/ U.
Ein ungeordneter (a, 2a)-Baum mit n Blättern hat eine Höhe von O(log n/ log a).
Damit ergeben sich folgende Laufzeiten für die einzelnen Operationen:
• Finde Minimum: in O(1).
• Lösche Minimum: entferne das Blatt (das durch den Minimumanzeiger gegeben ist), gehe aufwärts zur Wurzel und repariere den (a, 2a) Baum durch
Verschmelzen und Stehlen mit konstant vielen Operationen pro Knoten. Das
Minimum unter einem Knoten v wird durch das Minimum aus den Söhnen
gebildet, d.h. es kann in O(2a) = O(a) Schritten neu berechnet werden.
⇒ O(a · log n/ log a)
• Einfügen: analog zum Löschen werden Knoten gespalten und das Minimum
jeweils neu berechnet.
⇒ O(a · log n/ log a)
• Verringere Inhalt eines Blattes mit Zeiger. Wir verändern den Wert des Blattes
und gehen rückwärts zur Wurzel. Hat ein Knoten einen Minimalwert der
größer ist als der geänderte Wert, so biege das Minimum um.
Nach Lemma 4 ergibt sich eine Laufzeit von O(n·a·log n/ log a+m·log n/ log a).
Satz 5. Mit ungeordneten (a, 2a)-Bäumen kann das Kürzeste-Wege-Problem
mit folgenden Laufzeiten gelöst werden.
(i) O(n2 )
(ii) O(m log n)
Beweis: (i) wähle a = n
(ii) wähle a = 2.
2
6
INHALTSVERZEICHNIS
0.2.2
Fibonacci-Heaps
Definition 6. Ein heap-geordneter Baum ist ein Wurzelbaum mit Heapstruktur, d.h. der Schlüssel eines Knotens ist höchstens so groß wie die Schlüssel seiner
Söhne.
Definition 7. Der Rang rang(x) eines Knotens x ist die Anzahl der Söhne von
x.
Definition 8. Seien T1 und T2 zwei heap-geordnete Bäume. Die link-Operation
verschmilzt die beiden Bäume zu einem heap-geordneten Baum T.
Implementation der Link-Operation: Vergleiche die Inhalte der Wurzeln r 1
von T1 und r2 von T2 . Sei o.B.d.A. Inhalt von r1 ≤ Inhalt von r2 . Mache r2 zum
Sohn von r1 .
W1
W2
W1
S
S
B
B
B
S
S
j
T1
j
S
S
S
S T2 B
j
PP
B
B
T1
S
PP
S
S
S
PP
W2
P
P j
B
B
B
T2 B
B
B
⇒ O(1).
Definition 9. Ein Fibonacci-Heap ist eine Familie von (schlüssel)-disjunkten
heap-geordneten Bäumen mit
• Vater-Sohn-Zeiger
• Sohn-Vater-Zeiger
• Brüder in doppelt-verketteter Liste
• Wurzeln in zirkulärer Liste
• zusätzlicher Zeiger auf die Wurzel mit kleinstem Schlüssel.
7
INHALTSVERZEICHNIS
Wurzel mit kleinstem Schlüssel
l
-
l
J
J
l
- l
6
J
J
J
J
- J
l
j
A
A
A
Aj
-
j
- l
A
A
A
A
l
A
A
- AAl
In
jedem Knoten sind gespeichert:
• 4 Pointer für die Verwaltung des Heaps
• der Rang rang(x)
• ein weiteres Bit für “markiert” bzw. “unmarkiert”, dessen Bedeutung weiter
unten erklärt wird.
Einige Operationen auf F-heaps
• Vereinige: Vereinige die zirkulären Wurzellisten zu einer zirkulären Wurzelliste und setze den Zeiger auf die minimale Wurzel neu. Diese Operation läßt
sich wie folgt in O(1) Schritten durchführen. Seien H1 , H2 zwei F-heaps mit
minimalen Wurzeln W1 , W2 , wobei o.b.d.A. Inhalt von W1 ≤ Inhalt von W2 .
8
INHALTSVERZEICHNIS
'
$
=
e
Min
W1
Min
?
e
&
%
Wurzeln von H1
e
H
Z
~
Z
'
eW2
?
e
&
6
e
HH
%
Wurzeln von H2
W1=
HH
$
W2
HH H
H
HH
HH
e
6
HH
je
Wurzeln von H1 vereinigt H2
• Füge Schlüssel i in F-Heap H1 ein: Diese Operation ist ein Spezialfall
der Vereinige-Operation und läßt sich in O(1) Schritten ausführen:
1. erzeuge einen F-Heap H2 , der aus i besteht
2. vereinige H1 und H2
• Finde Minimum: durch Pointer in O(1)
• Lösche Minimum: Wenn wir das Minimum löschen, müssen wir die neue
“Wurzelliste” nach dem neuen Minimum durchsuchen. Um nicht bei verschiedenen Löschschritten dieselben Knoten als Minimumskandidaten vorzufinden,
ist es ratsam, mit dem Auffinden des neuen Minimums gleichzeitig einen neuen heap-geordneten Baum aufzubauen. Der folgende Algorithmus leistet dies:
1. lösche Minimum
2. konkateniere die Liste der übrigen Wurzeln mit der Liste der Söhne des
alten Minimums zu einer neuen Wurzelliste.
3. gehe die neue Wurzelliste durch, um das neue Minimum zu bestimmen.
4. falls keine zwei Wurzeln den gleichen Rang haben, Stop.
9
INHALTSVERZEICHNIS
5. andernfalls seien T1 und T2 zwei Bäume mit Wurzeln r1 , r2 und rang(r1 ) =
rang(r2 ). Führe link(T1 , T2 ) aus und gehe zu 3.
Implementation von Schritt 3 und 4:
Wir definieren ein Sortierfeld, Sortfeld [0 : M ax Rang], mit der Eigenschaft, daß
Sortfeld (i) auf eine Wurzel mit Rang i zeigt. M ax Rang ist der größte vorkommende Rang. Wir werden später zeigen, daß M ax Rang = dlog ne ist.
Sortfeld (i) = N il für 0 ≤ i ≤ MaxRang.
While Wurzelliste 6= ∅ do
entferne die erste Wurzel x aus der Liste
setze AktWurzel := x
setze AktRang := rang(x) = (# der Söhne von x)
if Schlüssel (x) < Schlüssel (M in) then M in := W ert(x)
while Sortf eld(AktRang) 6= Nil do
link (AktWurzel, Sortfeld(AktRang))
setze AktWurzel auf die Wurzel der vereinigten Bäume
Sortfeld (AktRang) := Nil
AktRang := AktRang +1
endwhile
Sortfeld (AktRang) := AktWurzel
endwhile
For i := 0 to MaxRang do
if Sortfeld (i) 6= N il then füge Sortf eld(i) in Wurzelliste ein
endfor
Lemma 10. Die Laufzeit für “lösche Min” beträgt O(MaxRang + Anzahl der
link-Operationen)
2
Beobachtung 11. Wenn wir auf einen anfänglich leeren F-heap nacheinander
und mehrmals die Operationen “Einfügen”, “Finde min”, “lösche min” anwenden,
so sind zu jedem Zeitpunkt die Bäume des F-heaps binomial, d.h.:
B0 = {r0 }
Bk = link(Bk−1 , Bk−1 )
10
INHALTSVERZEICHNIS
j
j
j
B0
j
%
j
% A
A
%
j
B1
B2
j
j
```
j
@
@
T
T
j
j
j
j
```
j
j
B3
Denn: lediglich “lösche min”verändert die Bäume und der obige Algorithmus behält
die binomiale Struktur bei.
Lemma 12.
(i) |Bk | = 2k
(ii) Die Wurzel von Bk hat k Söhne
(iii) x ∈ Bk ⇒ rang(x) ≤ k.
Beweis: Induktion über k.
(i) |Bk | = 2|Bk−1 | = 2 · 2k−1 .
(ii) # Söhne von Wurzel von Bk = 1+ # Söhne von Bk−1 .
(iii) x ∈ Bk−1 oder x ist die Wurzel von Bk .
2
Amortisierte Kosten der Operationen
Wir haben bisher worst-case-Abschätzungen für die Laufzeiten unserer Operationen
durchgeführt. Diese Operationen werden mehrmals hintereinander ausgeführt. Es
ist daher durchaus möglich, daß wir bei einer Ausführung Arbeit investieren, die
sich bei späteren Ausführungen durch eine geringere Laufzeit bezahlt machen. Die
Analyse wird üblicherweise mit amortisierten Kosten gemacht. Sei dazu zu jedem
Fibonacci-Heap H eine nichtnegative Zahl potential(H) gegeben, die wir später
geeignet spezifizieren.
Definition 13. Einer Operation Op, die den F-Heap H 1 in den F-Heap H2
überführt, ordnen wir wie folgt amortisierte Kosten zu:
amortisierteKosten (Op) = Lauf zeit(Op) + potential(H 2 ) − potential(H1 )
Bemerkung 14. Wir starten mit einem leeren F-Heap und führen eine Folge von
Operationen Op1 , Op2 , . . . , Opk durch, wobei Opi den F-Heap Hi−1 in den F-Heap
Hi überführt. Dann ergeben sich die amortisierten Gesamtkosten als Summe der
Laufzeiten + potential(Hk ). Da potential(Hk ) ≥ 0, gilt stets:
Laufzeit ≤ amortisierte Kosten
INHALTSVERZEICHNIS
11
Somit stellen die amortisierte Kosten eine obere Schranke für die Laufzeit dar.
Es reicht also, die amortisierten Kosten zu berechnen, die meist besser als die
Laufzeiten abgeschätzt werden können. Dabei ist es natürlich wichtig eine geeignete
Potentialfunktion zu wählen.
Definition 15. Sei H ein F-Heap mit Bäumen T1 , . . . , Tk . Das Potential von
H ist gegeben durch:
potential(H) = k = Anzahl der Bäume
Wir wollen jetzt die Operationen finde Min, füge ein und lösche Min noch einmal
amortisiert abschätzen.
• füge ein: amortisierte Kosten O(1)
• lösche Min: durch das Löschen der Wurzel in H1 erhöht sich die Anzahl
der Bäume in H2 um höchstens log n ≥ rang(Wurzel) und jeder link-Schritt
verringert die Anzahl um eins. Somit:
potential(H2 ) ≤ potential(H1 ) + log n − Anzahl der link-Operationen
Entsprechend ergeben sich die amortisierten Kosten von “lösche Min” als
höchstens (vergl. Lemma 10:
(log n+ Anzahl der link-Operationen) +(|Bäume inH 1 | + log n− Anzahl
der link-Operationen) −|Bäume in H1 | = O(log n).
• finde Min: amortisierte Kosten O(1)
• verringere: Gegeben ein Zeiger auf das Element i, verringere den Schlüsselwert von i um ∆ ≥ 0 : Wir können versuchen, ∆ zu subtrahieren und danach
die Heap-Struktur zu reparieren. Dies würde zu einer Laufzeit von O(log n)
führen und damit die Gesamtlaufzeit gegenüber den (a, 2a)-Bäumen nicht
verbessern. Wir wählen daher folgenden Ansatz:
Subtrahiere ∆ vom Schlüssel in i
Löse die Vater-Sohn-Verbindung von i zu seinem Vater und von i zu
seinen Brüdern
Verringere den Rang des Vaters
Nimm i in die Wurzelliste auf
Schreibe Minimalzeiger fort.
in O(1)
Aber: “verringere”verändert die Struktur, insbesondere die Binomialstruktur! Damit ist die Laufzeitabschätzung für lösche Min so nicht mehr gültig. Wir führen
daher eine Zusatzregel ein, die dafür sorgen wird, daß die Laufzeitschranke auch
weiterhin gelten wird (siehe Lemma 18).
Zusatzregel:
1. wird ein Knoten x in einem link-Schritt Sohn eines anderen Knotens, lösche,
wenn vorhanden, die Markierung von x
INHALTSVERZEICHNIS
12
2. wird die Verbindung zwischen x und seinem Vater p(x) gelöst und ist p(x) 6=
Wurzel:
(a) p(x) unmarkiert ⇒ p(x) wird markiert
(b) p(x) markiert ⇒ löse Verbindung p(x), p(p(x))
Bemerkung: Die Markierung zählt die von einem Knoten abgeschnittenen Söhne
und begrenzt deren Anzahl.
Vorsicht: der letzte Schritt kann propagieren.
Werden bei einer “verringere”-Operation die Verbindungen zwischen p(x) und p 2 (x)
bis hinauf zu pk (x) und pk+1 gelöst, so bewirkt die “verringere”-Operation k Folgeschnitte. Die Laufzeit ergibt sich damit als O(Anzahl der Folgeschnitte).
Bemerkung:
Durch die Zusatzregel haben wir erreicht, daß weiterhin die Größe eines jeden
Baumes exponentiell im Rang der Wurzel ist (Korollar 17). Überlegen Sie, daß dies
die einzige Eigenschaft binomialer Bäume war, die wir für die Laufzeitabschätzung
von lösche Min benutzt haben, so daß diese weiterhin gültig ist (vergl. Lemma
18). Andererseits läuft “verringere” auf den ersten Blick jetzt nicht mehr in O(1).
Hat eine “verringere”- Operation jedoch Folgeschnitte ausgelöst, verkleinert sich für
viele andere Knoten die Anzahl der Folgeschnitte, die “verringere” auslösen könnte.
Wir sind also in der typischen Situation, in der die Laufzeit mit Hilfe amortisierter
Kosten und einer geeigneten Potentialfunktion besser abgeschätzt werden kann. Wir
werden zeigen, daß bei mehreren Heap-Operationen die Summe der Folgeschnitte,
die von einzelnen “verringere”- Operationen hervorgerufen werden, durch die Anzahl
der “verringere”- Operationen beschränkt ist.
Lemma 16. Sei x ein Knoten in einem F-heap und y 1 , . . . , yk die augenblicklichen Söhne von x in der Reihenfolge ihrer Link-Verbindungen zu x. Dann ist
rang(yi ) ≥ i − 2.
Beweis: Zum Zeitpunkt als yi zum Sohn von x wurde, hatte x mindestens i −
1 Söhne, nämlich y1 , . . . , yi−1 . Gemäß der Link-Operation, hatten x und y i den
gleichen Rang, d.h. beide hatten Rang mindestens i − 1. Nach der Link-Operation
kann yi höchstens einen Sohn verloren haben, da sonst die Verbindung zwischen x
und yi gekappt worden wäre.
2
Korollar 17. Ein Knoten vom Rang k in einem F-Heap hat mindestens F k+2 ≥
τ k Nachfolger
(sich selbst eingeschlossen, F 0 = 0, F1 = 1, F = Fk + Fk−1 und
√
τ = (1 + 5)/2 der goldene Schnitt).
Beweis: Sei Sk die kleinstmögliche Anzahl von Nachfolgern eines Knotens vom
Rang k in einem F-Heap. Offensichtlich: S 0 = 1, und S1 = 2. Allgemein besteht
ein Baum mit Wurzeln vom Rang k zumindest aus der Wurzel, dem “ältesten”Sohn
und den Teilbäumen
Nach obigem Lemma ist
P unter den k − 1 “jüngeren”Söhnen. P
dann Sk ≥ 2 + ki=2 Si−2 , für k ≥ 2. Es ist: Fk+2 = ki=2 Fi + 2 für k ≥ 2,
P
Pk−1
denn 2 + ki=2 Fi = 2 + i=2
Fi + Fk = Fk+1 + Fk = Fk+2 per Induktion. Somit
Sk ≥ Fk+2 per Induktion und entsprechend Fk+2 ≥ τ k .
2
13
INHALTSVERZEICHNIS
Lemma 18. (Amortisierte Kosten von “lösche Min”) Die amortisierten Kosten
einer “lösche Min”- Operation in einem F-Heap, der durch die oben beschriebenen Operationen “finde Min”, “füge ein”, “lösche Min”, “verringere” verändert
wird, betragen O(log n)
Beweis: Für die Laufzeitabschätzung von “lösche Min”, haben wir den maximalen
Rang mit Hilfe der binomialen Bäume durch log n abgschätzt. Dies ist jetzt nicht
mehr möglich. Sei k der Rang des Minimums, dann gilt nach Korollar 17 τ k ≤ n
und somit
log n
max Rang ≤
≤ 1.5 log n
log τ
2
Sei ck, c ∈ IR+ eine Laufzeitabschätzung für die “verringere”-Operation mit k
Folgeschnitten
Definition 19. Potential (H) = c(Anzahl der Bäume + 2∗ Anzahl der markierten
Nichtwurzelknoten).
Lemma 20. Bei einer “verringere”-Operation mit k Folgeschnitten erhöht sich
das Potential erhöht sich um höchstens c(3 − k).
Beweis: Da k Folgeschnitte ausgeführt werden, waren p(x), . . . , pk (x) markierte
Nichtwurzeln, die zusammen mit x zu Wurzeln werden. Zudem ist p k+1 (x) Wurzel
oder unmarkiert. Im letzteren Fall wird sie zu einer markierten Nicht-Wurzel. Die
Anzahl der Bäume erhöht sich so um k + 1 und die Anzahl der markierten Nichtwurzeln sinkt um mindestens k − 1. Damit ergibt sich eine Potentialänderung um
höchstens c(3 − k).
2
Lemma 21. Die amortisierten Kosten einer “verringere”-Operation in einem
F-Heap, der durch die oben beschriebenen Operationen “finde Min”, “füge ein”,
“lösche Min” und “verringere” verändert wird, betragen O(1).
Beweis: Es bleibt lediglich die Aussage für die “verringere”-Operation zu zeigen.
Sei dazu k die Anzahl der Folgeschnitte.
Amortisierte Kosten
≤ ck + Potentialänderung
≤ ck + c(3 − k)
= 3c = O(1)
2
Satz 22. Wenn wir mit einem leeren F-Heap starten und eine Folge von HeapOperationen ausführen, so ist die Laufzeit durch die amortisierte Zeit beschränkt.
Beweis: Beide Potentialfunktionen sind positiv und am Anfang = 0 und somit
folgt die Behauptung mit Bemerkung 13.
2
Satz 23. Die Laufzeit eines Dijkstra-Algorithmus, der die Front mit Hilfe eines
F-Heaps verwaltet, beträgt O(m + n log n).
INHALTSVERZEICHNIS
14
Beweis: Nach Satz 22 ist die Laufzeit durch die amortisierten Kosten beschränkt.
Diese ergeben sich für jede Operation als Anzahl der Ausführungen dieser Operation mal ihren amortisierten Kosten. Insgesamt führen wir höchstens n füge-ein, n
finde-Min, n lösche-Min und m verringere Operationen durch, also ergibt sich eine
Laufzeit von O(n · 1 + n · 1 + n log n + m · 1) = O(m + n log n).
2
0.2.3
Buckets
Lemma 24. Sei d := min{dist(u) : u ∈ U } und C = max{c(e) : e ∈ E}. Für
alle v ∈ U gilt d ≤ dist(v) ≤ d + C.
Beweis: Induktion über die while-Schleife, wobei wir mit d k , distk , Uk die entsprechenden Größen vor Ausführung der k-ten Iteration bezeichnen.
Die Aussage ist offensichtlich richtig für k = 1. Sei u im Schritt k das Element mit
minimaler Distanz und v ∈ Uk . Nach Wahl von u ist dk ≤ distk (v). Ist v ∈ Uk−1 ,
so gilt per Induktion , daß distk (v) ≤ distk−1 (v) ≤ dk−1 + C ≤ dk + C. Ist
v∈
/ Uk−1 , so ist distk (v) = dk + c(u, v) ≤ dk + C.
2
Wir können daher die Menge U in C doppelt verketteten Listen Eimer (0), . . . ,
Eimer (C) verwalten, wobei die Liste Eimer(k) alle Knoten v ∈ U enthält, für
die gilt k = dist(v) mod (C + 1). Zusätzlich benutzen wir wieder einen Zeiger
assign(v), der von v auf dasjenige Listenelement der Liste der Eimer zeigt, das v
enthält.
Eimer (0),
Eimer (i)
Eimer (C)
Dist(v)mod(C + 1) = i ⇔ v ∈ Eimer (i)
• füge ein: Füge v in den Eimer Dist(v)mod(C + 1) ein.
• Finde Min: Sei i0 die Nummer des Eimers, der das letzte Minimum enthielt
i=0
While Eimer ((i0 + i)mod(C + 1)) = ∅ und i ≤ C do i = i + 1.
If i = C + 1
then Stop (Front ist leer)
else
das Minimum befindet sich im Eimer (i 0 + i)mod(C + 1).
endif
• lösche Min: Entferne das Minimum aus seinem Eimer.
• Verringere: Entferne v aus dem Eimer OldDist(v)mod(C + 1) und füge v
in den Eimer N ewDist(v)mod(C + 1) ein.
Lemma 25. Die Laufzeit des Dijkstra-Algorithmus mit Buckets beträgt O(n ·
|C| + m)
Beweis Füge-ein, Verringere und Lösche-Min können auf doppelt verketteten Listen in O(1) ausgeführt werden. Die Schleife in Find Min wird maximal C mal
durchlaufen also ist Find Min in O(|C|) und die Behauptung folgt mit Lemma 4.2
15
INHALTSVERZEICHNIS
0.2.4
Redistributive Heaps
Sei wie oben C = max cij und k = 1+dlog Ce. Im Unterschied zum vorigen EimerVerfahren, verwenden wir jetzt Eimer, deren Größen sich dynamisch ändern. Die
Inhalte der Eimer werden durch Listen contents(0), . . . , contents(k) repräsentiert.
Zusätzliche Zeiger assign(u) zeigen auf dasjenige Listenelement des Eimers, das
den Knoten u repräsentiert. Die k +1 Eimer B0 , . . . , Bk in einem redistributiven
Heap sollen folgende Bedingungen erfüllen:
• Bi enthält die Knoten v mit dist(v) ∈ [li , ui ] =: range(i)
• li > ui ⇒ Bi = ∅
• ui − li ≤ 2i−1 − 1
für i ≥ 1
• Weiter soll gelten:
1. dist(v) < ∞ ⇒ dist(v) ∈ [l0 , uk ]
2. v ∈ Bi , w ∈ Bj , i < j ⇒ dist(v) < dist(w)
S
3. ki=0 [li , ui ] = [l0 , uk ]
4. |range(0)| = 1, |range(k)| ≥ C
P
5. |range(i)| ≤ i−1
j=0 |range(j)| für i = 1, . . . , k
Die Knoten mit dist(v) = ∞ verwalten wir in einem weiteren Eimer B k+1 , um in
der Notation konsistent bleiben zu können.
Wir wählen am Anfang
range(0) = [0, 0]
range(i) = [2i−1 , 2i − 1] f ür alle i = 1, . . . , k,
was offensichtlich die obigen Bedingungen erfüllt. Die für die Implementation des
Dijkstra-Verfahrens notwendigen Operationen können nun auf R−Heaps so realisiert werden:
• Lösche: lösche Knoten u aus der Liste assign(u) : läßt sich in O(1) Schritten
durchführen
• Verringere: Wenn sich der Schüssel eines Knoten verringert, müssen wir
den Knoten aus der Eimerliste des Eimers, der ihn momentan enthält, entfernen und in eine neue Eimerliste wiedereinfügen. Diese Prozedur nennen wir
Wiedereinfügen.
• Wiedereinfügen: füge einen Knoten u, der durch einen Zeiger auf die Position in seinem Eimer gegeben ist, in einen neuen Eimer ein. Diese Operation
läßt sich wie folgt ausführen:
procedure Wiedereinfügen
(1) i = Eimer(assign(u))
(2) contents(i) = contents(i) − {u}
(3) while dist(u) ∈
/ range(i) do i = i − 1
INHALTSVERZEICHNIS
16
(4) contents(i) = contents(i) ∪ {u}
Lemma 26. r Aufrufe der Prozedur Wiedereinfügen benötigen höchstens O(r+
nk) Schritte.
Beweis: Jeder Aufruf benötigt O(1) Schritte und die Zeit, die die while-Schleife
verbraucht. Bei jedem Schritt der while-Schleife wird aber der Zeiger des Eimers um
1 vermindert, d.h. jeder Knoten u kann höchstens k + 1 mal neu eingefügt werden.
Damit ergibt sich eine Laufzeit von O(r + nk).
2
• Füge ein: Wie bereits gesagt, sind alle Knoten mit Dist = ∞ in einem
zusätzlichen Eimer enthalten. Die Prozedur “Füge ein” muß dann dasselbe
wie die Prozedur “Verringere” leisten.
• Finde Min: Finde einen Knoten j mit minimaler Distanz dist(j)
wie folgt
(1) Suche den ersten nichtleeren Eimer B p
(2) verteile den Inhalt von Bp auf die Eimer B0 , . . . , Bp
(3) gib den Inhalt von B0 zurück (bzw. von B1 , falls B0 = ∅).
Wir implementieren diese Idee in Form des folgenden Verfahrens:
i=0
while contents(i) = ∅ do i = i + 1
p=i
if p ∈
/ {0, 1} then
dmin = min{dist(j) : j ∈ contents(p)}
l0 = u0 = dmin
if p = k then
for i = 1 to k do
li = 2i−1 + dmin
ui = 2i − 1 + dmin
endfor
else
for i = 1 to p do
li = 2i−1 + dmin
ui = min{2i − 1 + dmin , up }
endfor
endelse
for each j ∈ contents (p) : REINSERT j
endif
if contents(0) 6= ∅ : gib einen Knoten v ∈ contents(0) zurück, andernfalls
einen v ∈ contents(1).
INHALTSVERZEICHNIS
17
Lemma 27. Es gilt stets [dmin , dmin + C] ⊆ [l0 , uk ]
Beweis: Diese Aussage ist offensichtlich zu Beginn des Verfahrens für l0 = 0, uk =
2k − 1 ≥ 2C − 1 und dmin = 0 erfüllt. Die einzige Operation, die die Struktur des
R-Heaps verändert, ist Finde Min. Sei dazu d0min ∈ Bp das neue Minimum. Es ist
l00 = d0min . Ist p = k, so gilt u0k = 2k − 1 + d0min ≥ d0min + 2C − 1. Ist p < k, so
gilt nach Eigenschaft 4, uk − lk + 1 ≥ C, und somit uk ≥ C + lk − 1 ≥ C + d0min ,
da d0min ∈
/ Bk . Damit folgt die Behauptung.
2
Lemma 28. Die Prozeduren Lösche, Wiedereinfügen, und Finde Min führen
R-Heaps in R-Heaps über.
Beweis: Lösche läßt offensichtlich die Bedingungen 1 - 5 invariant.
(ii) Bei Finde Min bleiben die Eigenschaften 2 - 5 per Konstruktion erhalten.
Die Eigenschaft 1 ergibt sich aus dem obigen Lemma.
(iii) Wiedereinfügen läßt die Struktur des R-Heaps unverändert; es ist lediglich
die Bedingung 1 zu überprüfen, nachdem die Distanz eines Knotens geändert wurde.
Sei also dist(j) = dist(i) + cij die neue Distanz. Dann ist l0 = dmin = dist(i) ≤
dist(j) = dmin + cij ≤ dmin + C ≤ uk nach obigem Lemma. Damit haben nach
Ausführung von Schritt 2 (Lösche) die Eimer wiederum R-Heap-Struktur.
2
Lemma 29. Gilt in der Prozedur Finde Min p ≥ 2, so wird der Inhalt des
0
Eimers Bp auf die neuen Eimer B00 , . . . , Bp−1
verteilt, d.h. Bp0 = ∅.
Beweis: Wir zeigen, daß Bp0 = ∅.
(i) p < k. Es ist up ≤ lp +|2p−1 |−1 < lp +2p−1 ≤ d0min +2p−1 . Nach Konstruktion
ist lp0 = 2p−1 + d0min und u0p = min{up , 2p − 1 + d0min } < lp0 . Somit ist Bp0 = ∅.
(ii) p = k : Es ist Bk0 = [d0min + C, d0min + 2C − 1]. Das letzte Intervall war
Bk = [lk , uk ], wobei lk ≤ d0min und uk ≤ lk + 2k−1 − 1 ≤ d0min + C − 1 Daraus
folgt, daß Bk ⊆ [l0 , d0min + C − 1]. Somit werden alle Knoten aus B k auf die Eimer
0
B00 , . . . , Bk−1
verteilt und Bk0 ist leer.
2
Satz 30. Das Dijkstra-Verfahren mit R-Heaps benötigt O(m + nlogC) Schritte.
Beweis: Lösche kann höchstens n-mal aufgerufen werden mit einer Laufzeit von
O(n). Wiedereinfügen wird höchstens m-mal aufgerufen, woraus sich eine Laufzeit
von O(m + nk) ergibt. Weiter wird Finde Min höchstens n-mal benutzt. Jeder
Aufruf benötigt höchstens O(k) Schritte, um einen ersten nichtleeren Eimer B p zu
finden, und höchstens O(k) Schritte, um die Eimer neu zu erzeugen. Ist p ≥ 1, so
werden zusätzlich noch O(|contents(p)|) viele Schritte für die Minimumsuche in
Bp durchgeführt. Da bei jedem Durchsuchen eines Eimer der Inhalt auf Eimer mit
kleinerem Index verteilt werden, kann die Gesamtanzahl der Suchschritte höchstens
O(nk) betragen.
Damit ergibt sich eine Gesamtlaufzeit von O(m + nk) = O(m + n log C).
2
18
INHALTSVERZEICHNIS
0.3
Skalierungs-Verfahren
Definition 31. Eine Abbildung d : V → IR heißt Näherungslösung, wenn folgende
Eigenschaften erfüllt sind:
(i) ds = 0,
(ii) di + cij ≥ dj ,
(iii) der maximale Abstand M axDist(i) von s nach i liegt im Intervall [d i , di + m].
Lemma 32. Gegeben eine Näherungslösung di , so läßt sich in O(m) Schritten
eine exakte Lösung berechnen.
Beweis: Setze c0ij = di + cij − dj . Es ist c0ij ≥ 0. Seien Dist0 (u) die im DijkstraVerfahren berechneten Distanzen bzgl. der Entfernungen c 0ij . Offensichtlich unterscheidet sich die Länge eines (s, u)-Weges bzgl. c0ij von der Länge dieses (s, u)Weges bzgl. cij nur um die Konstante du . Es gilt also stets Dist0 (u) = Dist(u)−du .
Mit (iii) folgt somit Dist0 (u) ≤ m. Daher läßt sich in O(m) Schritten mit Hilfe
eines Eimerverfahrens bei dem für jede mögliche Distanz ein Eimer zur Verfügung
2
gestellt wird, mit m Eimern eine Optimallösung bzgl. c0ij berechnen.
Lemma 33. Sei di die doppelte Distanz von s nach i bzgl. der Kantenbewertung
c0ij = bcij /2c. Dann ist di eine Näherungslösung bzgl. cij .
Beweis: (i) ds = 0
(ii) Es gilt nach Beendigung des Dijkstra-Verfahrens:
cij
Dist0 (i) + c0ij ≥ Dist0 (j) ⇒ Dist0 (i) + b c ≥ Dist0 (j)
2
cij
0
≥ Dist0 (j)
⇒ Dist (i) +
2
⇒ 2 ∗ Dist0 (i) + cij ≥ 2 ∗ Dist0 (j)
c
(iii) Da 2b 2ij c ≤ cij ≤ 2b
m = di + m.
cij
2 c+1,
⇒ di + cij ≥ dj
folgt di = 2∗Dist0 (i) ≤ Dist(i) ≤ 2∗Dist0 (i)+
2
Skalierungsalgorithmus
(1) Ist cij ≤ m
n ∀(ij) ∈ E, so verwende Eimer-Verfahren.
(2) Andernfalls berechne rekursiv die Distanzen i von s nach i, i ∈ V bzgl. bc ij /2c
und die Näherungslösung di .
(3) Berechne aus der Näherungslösung di die Distanz Dist(i) bzgl. cij .
⇒ Laufzeit O(m log C), wobei C = max{cij , (ij) ∈ E}
0.4
D’Esopo-Pape-Algorithmus
Der Ansatz von D’Esopo und Pape versucht, die zeitaufwendige Minimumssuche
zu vermeiden. Dabei wird aber in Kauf genommen werden müssen, daß ein Knoten
mehrmals markiert wird.
INHALTSVERZEICHNIS
0.4.1
19
D’Esopo-Pape-Verfahren
Input: (Di)-Graph G = (V, E), Gewichte c(e) ∀e ∈ E, so wie Startknoten s
Output: Kürzeste Wege von s nach v ∀v ∈ V und ihre Längen.
Datenstrukturen: Dist(v), V or(v) ∀v ∈ V wie gehabt.
(1) Dist(s) := 0 und Dist(v) = ∞, V or(v) := s ∀v ∈ V \{s}
(2) Initialisiere eine Schlange Q und setze s in Q
(3) Hole das erste Element aus der Schlange, sagen wir u
for all (u, v) ∈ E do
if Dist(u) + c(u, v) < Dist(v) then
Dist(v) := Dist(u) + c(u, v);
V or(v) = u
if v noch nicht in Q war setze v an das Ende von Q
else if v jetzt nicht in Q, setze v an den Anfang von Q
endif
endfor
If Q 6= ∅ gehe zu 3
If Dist(v) < ∞, so enthält Dist(v) die Länge des kürzesten (s, v) Weges
If Dist(v) = ∞, so gibt es keinen (s, v)-Weg.
Lemma 34. Der D’Esopo-Pape Algorithmus arbeitet korrekt.
Beweis: Für v ∈ V sei P ape(v) die vom d’Esopo-Pape-Algorithmus berechnete
Distanz. Offensichtlich gilt P ape(v) ≥ Dist(v) für alle v ∈ V.
Angenommen P ape(v) > Dist(v) für mindestens einen Knoten. Unter all diesen, wähle einen mit Dist(v) minimal und unter diesen wiederum einen, dessen
kürzester Weg möglichst wenige Knoten enthält. Sei v ein solcher Knoten und u
der Vorgänger von v auf einem kürzesten Weg. Per Konstruktion gilt Dist(u) =
P ape(u).
Zu dem Zeitpunkt, an dem u zum letzten Mal aus Q entfernt wird, muß
Dist(u) = P ape(u) gelten, denn die Pape-Distanz von u bleibt danach unverändert.
Danach gilt:
P ape(v) ≤ P ape(u) + c(u, v) = Dist(u) + c(u, v) = Dist(v)
2
0.5
2-Listen-Verfahren und Threshold-Verfahren
Während der d’Esopo-Pape-Algorithmus eine nicht polynomial beschränkte Laufzeit
hat, läßt sich die folgende Variante durch O(n · m) beschränken.
INHALTSVERZEICHNIS
0.5.1
20
2-Listen-Verfahren
Setze Dist(u) = ∞, V or(u) = ∅ ∀u ∈ V \{s, Dist(s) = 0 und k = 0.
Erzeuge zwei Listen (Stacks oder Queues) N EXT = ∅ N OW = {s}.
Falls N OW = ∅, gehe zu 4. Andernfalls wähle u ∈ N OW.
for all (u, v) ∈ E do
if Dist(v) > Dist(u) + c(u, v), then
Dist(v) = Dist(u) + c(u, v)
Vor (v) = u
If v ∈
/ N OW ∪ N EXT : füge v zu N EXT hinzu
endif
endfor
gehe zu 2.
2. If N EXT = ∅, ST OP
Else setze N OW = N EXT, N EXT = ∅, k = k + 1 und gehe zu 2.
endif
(1)
(2)
(3)
1.
Lemma 35. Sei dk = min{Dist(u) : u ∈ N EXT } am Anfang von Schritt 4 in
der k-ten Iteration. Dann gilt:
(i) dk ≤ dk+1
(ii) für alle u ∈ N EXT mit Dist(u) = dk ist ein kürzester Weg gefunden und
u wird nicht mehr in einer N EXT -Liste auftauchen.
Beweis: (i) Jeder Knoten in der N EXT -Liste der Iteration k+1 hat einen direkten
Vorgänger aus der N EXT -Liste zum Zeitpunkt k. Da c ij ≥ 0, folgt dk ≤ dk+1 .
(ii) folgt aus (i), da ein solcher Knoten nicht in N OW aufgenommen wird.
2
Satz 36. Der 2-Listen-Algorithmus berechnet die Länge der kürzesten Wege
und hat eine Laufzeit von O(n · m).
Beweis: In jeder Iteration werden schlimmstenfalls alle Kanten durchsucht. Da
nach obigem Lemma in jeder Iteration stets mindestens einen Knoten der kürzeste
Weg gefunden wird, kann es höchstens n Iterationen geben.
2
Beobachtung 37. : Das Lemma und der obige Satz benötigen lediglich die Tatsache, daß mindestens einer der Knoten u mit Dist(u) = d k von N EXT nach
N OW geschoben wird. Es muß also nicht die gesamte Liste übernommen werden.
0.5.2
Threshold-Algorithmus
Zusatzregel: Wähle eine Konstante K ∈ IN und modifiziere Schritt 4:
If N EXT = ∅, STOP
INHALTSVERZEICHNIS
21
else
setze K Knoten aus N EXT nach N OW , die mindestens einen
Knoten u enthalten, für den Dist(u) = d.
k =k+1
gehe zu 2
endif
z.B. wähle K − 1 beliebige Knoten und einen, für den Dist(u) = d.
Satz 38. Der Threshold-Algorithmus berechnet kürzeste Wege und hat eine
Laufzeit von O(n2 ).
Beweis: Die Korrektheit folgt aus den obigen Bemerkungen. Die Liste N OW
enthält höchstens K Knoten, von denen höchstens K(n − 1) Kanten ausgehen.
D.h. in jeder Iteration sind höchstens O(n) Kanten zu benutzen.
2
0.6
Future-Cost-Verfahren
Wie verdeutlichen die Idee des Future-Cost-Verfahrens zunächst an einem Beispiel:
Angenommen, ich suche den kürzesten Weg von Köln nach München. Der Graph
besteht z.B. aus dem Fernstraßennetz der Bundesrepublik, Knoten sind Städte bzw.
Kreuzungen oder Abzweigungen von Straßen.
Nach Korollar 3 genügt es, den Dijkstra-Algorithmus zu stoppen, sobald der
Knoten “München”in M liegt. Allerdings wird dann immer noch z.B. Hamburg in
M aufgenommen, da es näher zu Köln liegt als München. Dabei ist die Berechnung
des Weges nach Hamburg unnötig, da es offensichtlich nicht auf dem optimalen Weg
von Köln nach München liegt. Allein die Luftlinien-Entfernung zwischen Hamburg
und München ist länger als der Weg von Köln nach München und bekanntlich ist
kein Weg über Straßen kürzer als die Luftlinie.
Die Idee ist nun, solche leicht berechenbaren unteren Schranken (wie hier die
Luftlinie zwischen den Städten) zur Vermeidung unnötiger Berechnungen zu nutzen:
Sei f : V × V → IR+
0 eine Funktion mit f (v, v) = 0 für alle v ∈ V und
f (v, w) + f (w, x) ≥ f (v, x) für alle v, w, x ∈ V für die gilt:
f (v, w) ist untere Schranke für die Länge des kürzesten Weges von v
nach w; v, w ∈ V.
Um den kürzesten Weg von s nach t zu finden (s, t ∈ V ), definieren wir: c 0 (v, w) :=
c(v, w) + f (w, t) − f (v, t) für alle v, w ∈ V.
22
INHALTSVERZEICHNIS
Wie man leicht sieht, gilt c0 (v, w) ≥ 0, für alle v, w ∈ V.
= c(v, w) + f (w, t) − f (v, t) ≥ f (v, w) + f (w, t) − f (v, t) ≥ 0.
c0 (v, w)
Weiter gilt für alle Wege P von s nach t:
c0 (P ) = c(P ) − f (s, t)
Der kürzeste Weg von s nach t bzgl. c entspricht also dem kürzesten Weg bzgl.
c0 . Damit ist es zulässig, den Algorithmus bzgl. der Kosten c 0 laufen zu lassen.
Entsprechend gilt für alle Knoten u ∈ V, Dist0 (u) = Dist(u) − f (s, t) + f (u, t).
Das bedeutet, daß die untere Schranke für die restliche Entfernung f (u, t) auf die
Kosten Dist(u) addiert wird und so Knoten mit großer Entfernung zu t vermieden
werden können. Je schärfer die untere Schranke f ist, desto effektiver arbeitet das
Verfahren. Man überlege sich, wie sich der Dijkstra im schlechtesten Fall (f = 0)
und im günstigsten Fall (f (v, w) ist minimale Weglänge von v nach w) verhält.
Beachten Sie, daß f schnell berechenbar sein muß, da es bei jeder Kantenlänge
benötigt wird. Man beachte weiter, daß das Future-Cost-Verfahren mit anderen
Kürzeste-Wege-Verfahren kombinierbar ist.
c0
0.7
LP-Formulierung
Die Bestimmung eines kürzesten (s, t)-Weges läßt sich auch als ein lineares Optimierungsproblem formulieren.
Sei dafür A die n × m Knoten-Kanten-Inzidenzmatrix mit

 +1 die Kante j beginnt in i
aij =
−1 die Kante j endet in i

0 sonst
und bT = (1, 0, . . . , 0, −1) ∈ IRn .
Beispiel:
1 ea
Q
3
Q
Q 4
Q
Q
Q
s
Q?e t
*
3
s eH
H
HH
Hj
H
? 5
2
e
b
23
INHALTSVERZEICHNIS

s
1 1 0 0
0
a 
−1
0
1
1
0

A=
b  0 0 0 −1 −1
t
0 0 0 −1 −1




Jeder einfache (s, t)-Weg entspricht einem 0 − 1-Vektor x = (x 1 , . . . , xm ) mit
xj = 1 ⇔ Kante j liegt auf dem Weg und
Ax = b,
das heißt : es führt genau eine Kante aus s heraus, genau eine Kante nach t
hinein und jeder andere Knoten wird entweder überhaupt nicht erreicht, oder es
führt genau eine Kante hinein und eine hinaus.
Somit: Jeder Inzidenzvektor x eines Weges löst
Ax = b
x
≥0
Umgekehrt: Betrachte das lineare Programmierungsproblem
min cx
(LP ) Ax = b
x≥0
Lemma 39. Wenn das LP eine Optimallösung hat, dann auch eine, die Inzidenzvektor eines (s, t)-Weges ist.
Beweis: Sei y eine Optimallösung. Betrachte den Teilgraphen G 0 = (V 0 , E 0 ) der
durch die Kanten e mit ye > 0 induziert wird. Ist y nicht schon der Inzidenzvektor
eines Weges, so existieren Knoten u, v ∈ V 0 , die in G0 durch zwei kantendisjunkte
Wege P, P 0 miteinander verbunden werden. O.B.d.A. sei c(P ) ≤ c(P 0 ). Sei ye =
min{yf : f ∈ P 0 }. Leite wie folgt um:

, falls f ∈
/ P ∪ P0
 yf
0
y − ye , falls f ∈ P 0
yf =
 f
yf + ye , falls f ∈ P
y 0 ist zulässig für (LP) und cy 0 ≤ cy, d.h. y 0 ist wiederum optimal. Durch wiederholte Anwendung des obengenannten Verfahrens erhalten wir eine Optimallösung
x, die Inzidenzvektor eines (s, t)-Weges ist.
2
Der Beweis zeigt unmittelbar, daß jeder einfache (s, t)-Weg in G 0 ein kürzester
(s, t)-Weg in G ist.
24
INHALTSVERZEICHNIS
Betrachte das zu (LP) duale Programm:
.
(DP )
max ys − yt
yA ≤ c,
.
wobei die Nebenbedingungen von der Form
yi − yj ≤ cij
sind.
Lemma 40. Sei y eine dual-zulässige Lösung. Dann liefert f (v, w) = yv − yw
eine untere Schranke für die Länge des kürzesten (v, w)-Weges.
Beweis: Sei P = u0 , u1 , . . . , uk mit u0 = v, uk = w ein kürzester (v, w)-Weg. Es
ist
c(P ) =
k−1
X
i=0
c(ui , ui+1 ) ≥
k−1
X
i=0
yui − yui+1 = yu0 − yuk = yv − yw .
2
Da f offensichtlich eine Metrik ist, lassen sich die dual-zulässigen Lösungen im
future-cost-Verfahren verwenden.
Literaturverzeichnis
[1] Ravindra K. Ahuja, Kurt Mehlhorn, James B. Orlin and Robert R. Tarjan.
Faster Algorithms for the Shortest Path Problem. Journal of the ACM, 37
(1990), 213-223
[2] James D. Divoky and Ming S. Hung Performance of Shortest Path Algorithms in Network Flow Problems. Management Science, Vol. 36, No. 6,
1990
[3] Fred Glover, Randy Glover and Darwin Klingman. Computational Study of
an Improved Shortest Path Algorithm. Networks, 14 (1984), 25-36
[4] Fred Glover, D. Klingmann and N. Phillips. A New Polynomially Bounded
Shortest Path Algorithm. Operations Research, Vol. 33, 1985, 65-73
[5] Donald B. Johnson. A Priority Queue in which Initialization and Queue
Operations take O(log log D) Time. Mathematical Systems Theory, 15, 295309, 1982
25
Herunterladen