+ |V

Werbung
Kürzeste Wege Problem
Das Ergänzende Kapitel zu DAP 2
Bernchteine Elena
Kürzeste Wege
In kantenbewerteten Graphen war die Distanz zwischen zwei Knoten definiert als
die Länge des kürzesten Weges zwischen ihnen.
Gegeben sein ein Weg p = (v0 ,v1 ,... ,vn ) in einem Graphen G
mit Kantengewicht w .
Die Länge des Weges ist dann definiert als
w(p) = 
n
(vi-1 , vi )
i =1
Bezeichnen wir mit P ( u,v ) die Menge der Wege von Knoten u nach Knoten v, so
ist die Distanz zwischen u und v
( u,v ) = min { w ( p )  p  P ( u,v ) } falls P ( u,v )  

sonst
Ein kürzester Weg p von u nach v ist dann ein Weg p P (u,v) mit
w( p ) = (u,v).
Problemvarianten
Das Problem der kürzesten Wege (KW-Problem) tritt in den folgenden Varianten
auf:
1
1:1-KW-Problem (single-pair shortest-path problem)
Gesucht ist der kürzeste Weg von einem Knoten u zu einem Knoten v.
2
1:n-KW-Problem (single-source shortest-path problem)
Gesucht sind die kürzesten Wege von einem Quellknoten u zu allen anderen
Knoten v.
3
n:1-KW-Problem (single-destination shortest-path problem)
Gesucht sind die kürzesten Wege zu einem Zielknoten v von allen anderen
Knoten u.
4
n:n-KW-Problem (all-pairs shortest-path problem)
Gesucht sind kürzesten Wege zwischen allen Knoten des Graphen.
Anmerkungen:
• Problem 3 kann auf Problem 2 zurückgeführt werden (und umgekehrt), indem die
Richtung der Kanten vertauscht wird. In ungerichteten Graphen sind die beiden
Probleme identisch
• Eine Lösung für Problem 1 fällt Teil eines Lösung für Problem 2 ab. Außerdem ist
kein spezifischer Algorithmus für Problem 1 bekannt, der asymptotisch schneller
wäre als die besten Algorithmen für Problem 2
Kanten mit negativen Gewichten
Kanten mit negativen Gewichten sind zwar untypisch für KW-Probleme, können
jedoch gelegentlich vorkommen.
Sie sind tolerierbar, solange keine vom Quellknoten erreichbare Zyklen negativer
Länge entstehen.Ein kürzester Weg wäre dann nicht mehr wohldefiniert.
Einige Algorithmen verlangen nichtnegative Gewichte, andere tolerieren sie, d.h. sie
produzieren ein korrektes Ergebnis, solange keine negativen Zyklen auftreten.
Repräsentation kürzester Wege
In der Regel interessiert man sich nicht nur für die Länge eines kürzesten Weges,
sondern auch für den kürzesten Weg selbst.
Bei dem 1:n - KW-Problem, das wir betrachten wollen, bietet sich wieder die
Verwendung eines Feldes pred[ ] an, in dem für jeden Knoten v dessen Vorgänger u
auf dem kürzesten Weg von einem Quellknoten s nach v gespeichert ist
(vgl. Breitensuche)
pred[ ] definiert einen Baum mit Wurzel s , der die kürzesten Wege zu allen anderen
Knoten enthält.
Wie wir sehen werden, genügen die kürzesten Wege dieser Baumstruktur.
Eigenschaften der KW-Bäume
Graph G=(V,E) –gewichtet, gerichtet; w : E  R –Gewichtsfunktion,
s – Quellknoten, G hat keine Zyklen negativer Länge
1. Nach der Initialisierung führt man eine Reihenfolge von
Relaxationsschritten an der Kanten von G so, dass s eine Wurzel ist und aus
dieser Wurzel s einen gerooteten Vorgänger-Teilgraph Gpred entsteht.
2. Nach der Initialisierung führt man eine Reihenfolge von
Relaxationsschritten an der Kanten von G so, dass d[v]= ( u,v ) ist für alle
v aus V. Daraus folgt, unser Vorgänger-Teilgraph Gpred – ein gerooteter aus
der Wurzel s KW-Baum .
Beispiel:
Gerichteter Graph mit zwei unterschiedlichen KW-Bäumen mit Wurzel 0
Eigenschaften kürzester Wege
Lemma: (Optimale Substruktur)
Gegeben sei ein Graph G = (V,E) mit Kantengewicht w . Sei p = ( v0 ,v1 , ...,vn ) ein
kürzester Weg von v0 nach vn . Sei pik = (vi , vi+1 ,... ,vk ) mit 0  i  k  n
ein Teilweg von p.
Dann ist pik = (vi , vi+1 ,… ,vk ) ein kürzester Weg von vi nach vk .
Beweis:
Wenn wir p zerlegen in Teilwege p0i , pik und pkn ,dann gilt:
w(p) =w( p0i) + w( pik) + w( pkn)
Wir nehmen nun an, es gebe einen Weg p'ik von v0 nach vk mit w(p'ik ) < w(pik ) .
Dann ist p' = p0i , pik , pkn ein Weg von v0 nach vn mit
w(p') = w( p0i) + w(p'ik) + w( pkn) < w( p0i) + w( pik) + w( pkn) = w( p)
Dies ist ein Widerspruch zur Annahme, dass p ein kürzester Weg ist .
Korollar:
Gegeben sei ein gerichteter Graph G = (V,E) mit Gewichtsfunktion w : E R
Angenommen , es gebe einen kürzesten Weg p von s nach v , der man so
beschreiben kann : s P  u
v ( mit dem Knoten u und dem Weg p). Daraus folgt
,dass das Gewicht des KW von s nach v ist :
((s,v) – Distanz zwischen s und v (kürzester Weg von s nach v)
(s,v ) = (s,u ) + w(u,v)
Beweis:
(s,v ) = w(p)
= w(p ) + w(u,v)
= (s,u ) + w(u,v) qed.
Lemma:
Gegeben sei ein GraphP‘ G = (V,E) mit Kantengewicht w und
einem Ausgangsknoten s .
Dann gilt für alle Kanten ( u ,v ) E : (s,v )  (s,u ) + w(u,v)
Beweis :
1.
Es gibt einen KW von s nach v , aber nicht über u
(s,v ) < (s,u ) + w(u,v) ist.
2. Es gibt einen KW von s nach v über diesen Knoten u :
(s,v ) = (s,u ) + w(u,v) qed.
3. Es gibt keinen KW von s nach v entweder über diesen Knoten u oder nicht über
diesen Knoten u :
(s,v ) < (s,u ) + w(u,v) ist.
Relaxation
Zum Begriff der Relaxation
Wir verwenden während der Berechnung Schätzungen d(v) (obere Schranken) für
die Distanz zwischen Anfangsknoten s und allen anderen Knoten v.
Am Anfang werden alle oberen Schranken (mit Ausnahme von s) auf „unendlich“
gesetzt.
Anschließend findet Schritt für Schritt ein Relaxationsvorgang statt:
Es wird für eine Kante (u,v) geprüft, ob sich durch Berücksichtigung dieser Kante
die bisher gefundene Distanz d(v) (d(v) =(s,v) ) von s nach v „entspannt“.
void relax(index u, index v)
{ if (d[v] > d[u] + w(u ,v)) d[v] = d[u] + w(u ,v);
pred[v]=u;}
Eigenschaften der Relaxation
1.
Nach der Relaxation an der Kante (u,v): d[v] <=d[u] + w(u,v).
Beweis: a)Vor der Relaxation d[v] <=d[u] + w(u,v) - d[v] bleibt nach der
Relaxation unverändert.
b) Vor der Relaxation d[v] >d[u] + w(u,v) - nach der Relaxation
d[v] =d[u] + w(u,v) . qed
2.
d[v] = (s,v) = 
Das heißt, es gibt keinen KW zwischen s und v.
3.
s u
v - KW und Vor der Relaxation d[u] = (s,u) , daraus folgt nach
der Relaxation d[v] = (s,v) .
Beweis:
Nach der Relaxation d[v] <=d[u] + w(u,v)
= (s,u) + w(u,v)
= (s,v)
Nach Def. d[v]>= (s,v) , daraus folgt d[v] = (s,v) . qed
Beispiel(Relaxation an der Kante (u ,v) )
u
5
2
5
2
u
(a)
v
9
u
v
u
7
5
2
v
6
5
2
v
6
(b)
Im Fall (a) d[v] > d[u] + w[u,v] ,  d[v] wird gewechselt
Im Fall (b) d[v]  d[u] + w[u,v] ,  d[v] bleibt unverändert
Dijkstras Algorithmus
Die verschiedenen Kürzeste-Wege-Algorithmen unterscheiden sich im wesentlichen
in der Reihenfolge, in der Kanten zur Relaxation aufgegriffen werden.
Dijkstras Algorithmus geht davon aus,dass alle Kantengewichte nichtnegativ sind.
• Alle Knoten werden nach ihrer bisher gefundenen Distanz d(v) aufsteigend
geordnet in einer geeigneten Datenstruktur Q gehalten (am besten
Prioritätswarteschlange mit Heap).
• Der nächste Knoten u wird aus Q entfernt und alle von ihm ausgehenden Kanten
werden „relaxiert“.
• Bei den Endknoten v der Kanten (Nachbarn von u) wird u als Vorgänger im KWBaum eingetragen, falls sich die Distanz d(v) verringert hat, also (u,v) eine
Baumkante wird
• Der Vorgang wird solange wiederholt, bis Q leer geworden ist .
Komplexität von Dijkstras KW-Algorithmus
• Jede remove-Operation der Prioritätenwarteschlange benötigt O(log|V|)
Schritte. Insgesamt werden |V| dieser Operationen benötigt.
• Der Aufbau des Heaps der Warteschlange kostet O(|V|)
• Die Modifikation der d -Werte (relax) impliziert ein Umordnen des Heaps,
das in O(log|V|) Schritten durchgeführt werden kann .Höchstens |E| dieser
Operationen sind erforderlich.
•
Wir erhalten also
O(|V| log|V| + |E| log|V|) = O((|V|+|E|) log|V|) = O(|E| log |V|)
Fords Algorithmus (Bellman-Ford)
• Der KW-Algorithmus nach Ford setzt keine nichtnegativen Gewichte voraus.
• Er benutzt ebenfalls das Relaxationsprinzip. Es wird also in jedem
Iterationsschritt für jede Kante (u,v) geprüft,ob ihre Verwendung die Distanz vom
Quellknoten v0 zu ihrem Endknoten v reduziert.
Es wird so lange iteriert, bis keine Verbesserungen mehr möglich sind.
• Bei Existenz negativer Zyklen würde dies bedeuten , dass der Algorithmus nicht
stoppt.
• Da jeder kürzeste Weg jedoch aus höchstens |V|-1 Kanten besteht, kann man
sich überlegen, dass |V|-1 Iterationsphasen ausreichen, um kürzeste Wege zu
berechnen (falls existent, d.h. vom Quellknoten zu ihrem Endknoten kann man
höchstens |V|-1 Kanten besuchen , sonst haben wir einen Zyklus negativer Länge)
• In jedem Iterationsschritt i entstehen Teillösungen, d.h. kürzeste Wege mit einer
Kantenanzahl von i.
BELLMAN-FORD(G , w, s)
1 initialize - single - source(G, s)
2 for i ← 1 to |V [G] | - 1
3
do for each edge (u, v) E [G]
4
do Relax(u,v,w)
5
for each edge (u, v)  E [G]
6
do if d[v] > d[u] + w(u,v)
7
then return FALSE
8
return TRUE
BELLMAN-FORD shortest path (V, E, vo , p) {
// berechne SSSP von vo zu allen anderen Knoten
// falls es keine Zyklen negativer Länge gibt, gib aus „nicht gefunden“
// sonst gib aus „gefunden“ und p enthält den kürzesten Weg
for (each v  V) {
d[v] =  ; p[v] = undefined; }
d [v0]= 0;
for (index i = 1; i <|V| -1; i ++ ) {
for (each edge (u, v)  E[G] ) {
if (d[v] > d[u] + w(u,v) ) // Relaxation
{ d[v] = d[u] + w(u,v) ; p[v] = u ; }}
// falls vorkommen, p enthält einen kürzesten Weg
for (each edge (u, v)  E[G] ) // überprüfe für negative Gewichte
{ if (d[v] > d[u] + w(u,v)) return FALSE ;
return TRUE; }}}
Beispiel
(Bellman-Ford-Algorithmus für negative Gewichte)
Beispiel
(Bellman-Ford-Algorithmus für negative Gewichte)
6

-2
6
0
5
-3
8
-4
2
7
7
7

9
für i =1
Wir betrachten die vom Quellknoten 0 ausgehenden Kanten
w(0,1)= 6 und w(0,3)=7
d[1] = 6
und d[3] = 7
Beispiel
(Bellman-Ford-Algorithmus für negative Gewichte)
1
6
1

6
-2
6
0
5
2
7
3
7
0
-3
8
4
7
7
3
7
-4
2

9
4
-2
-4
2
7
5
6
-3
8
2
2
9
4
für i = 2
Wir betrachten die vom Quellknoten 0 über einen Zwischenort ausgehende Kanten
w(0,1) , w(1,4)
und
w(0,3),w(3,2)
d[4] = d[1] + w(1,4)= 6+(-4)=2 und d[2] = d[3] + w(3,2) =7+(-3)=4
Beispiel
(Bellman-Ford-Algorithmus für negative Gewichte)
1
6
5
7
0
4
-2
-3
8
2
3

9
7
4
2
7
3
2
9
2
5
2
für i = 3
4
-2
6
-3
8
7
-4
7
2
7
3
2
9
4
Wir betrachten die vom Quellknoten 0 über 2
Zwischenorte ausgehende Kanten
w(0, 3),w(3, 2),w(2,1)
d[1] = d[2] + w(2,1)= 4+(-2)=2
7
-4
-4
7
0

6
2
6
-3
8
7
1
1
-2
6
0
5
2
4
Beispiel
(Bellman-Ford-Algorithmus für negative Gewichte)
1
5
6
0
-4
7
2
7
3
2
9
5
4
0
4
-2
-3
8
4
-3
8
7
-4
7
2
7
3
9
7
-4
7
2
7
3
2
9
4
für i = 4
-2
6
7
0
4
2
2
-3
8

1
-2
6
7
9
3
4
5
6
2
7
2
2
-4
7
5

6
-3
8
0
2
1
-2
6
1
2
2
4
Wir betrachten die vom
Quellknoten 0 über 3
Zwieschenorte ausgehende
Kanten
w(0, 3),w(3, 2),w(2,1),w(1,4)
d[4] = d[1] + w(1,4)= 2+(-4)= - 2
Beispiel
(Bellman-Ford-Algorithmus für negative Gewichte)
1
5
6
0
2
7
7
3
2
9
5
4
0
4
-2
6
-4
7
4
2
2
-3
8

1
-2
6
7
9
3
4
5
0
4
-2
6
2
7
2
2
-3
8
-3
8
7
-4
7
2
7
3
9
2
4
7
-4
-4
7
5

6
-3
8
0
2
1
-2
6
1
2
7
2
7
3
2
9
4
Nach der Relaxation haben wir
keine vom Quellknoten 0
erreichbare Zyklen negativer
Länge
Komplexität des Ford-Algorithmus
• Die Initialisierung besteht aus Q (|V|) Schritten
• Die innere for-Schleife besteht aus der Relaxationsoperation (O(1)) und wird
jeweils |E| mal ausgeführt, d.h. ihr Aufwand beträgt O(|E|)
• Die äußere for-Schleife wird |V | - 1 mal ausgeführt, jeweils mit einem Aufwand
von O(|E| ) , d.h. die geschachtelte for-Schleife ist mit O(|V|* |E|) zu kalkulieren
• Die nachfolgende Prüfung auf Existenz negativer Zyklen kostet O(|E|)
• Die Gesamtkomplexität des Ford-Algorithmus beträgt daher O(|V|* |E|) .
Das n : n – KW - Problem (all - pairs shortest paths)
• Kürzeste Wege zwischen allen Knoten des Graphen erhält man, indem man für
jeden Knoten das 1 : n - Problem löst, d.h.den Dijkstra - oder den Ford-Algorithmus
|V| mal aufruft.
• Dies führt zu einer Gesamtkomplexität von O((|V|2*E ) (Ford-Algorithmus) bzw.
O(|V|* |E|log|V|) (Dijkstra-Algorithmus)
• Bei dünn vermaschten Graphen, z.B. wenn |E| = O (|V|), und nichtnegativen
Gewichten ist diese Vorgehensweise zu empfehlen und der Dijkstra-Algorithmus
einzusetzen.
• In anderen Fällen gibt es spezielle Algorithmen für das n : n – KW - Problem
Johnson‘s Algorithmus
• Der KW – Algorithmus nach Johnson ist ein APSP-Algorithmus. Er benutzt
Dijkstra und Bellman-Ford Algorithmen als Hilfsalgorithmen und führt eine
Rekalibrierung durch.
• Es wird zuerst mit Bellman-Ford die Existenz negativer Zyklen geprüft
• Dann wird in zweitem Schritt, falls wir keinen negativen Zyklus haben,
rekalibriert, so bekommen wir einen Graph, dessen Kanten positiv sind .
• Weiter können wir Dijkstra den kürzesten Weg für alle Knoten berechnen
Bestimmung der Rekalibrierung :
Füge einen zusätzlichen Knoten s zum Graph hinzu und verbinde diesen Knoten s
mit jedem anderen Knoten v  V [G] durch eine Kante der Länge 0.
Berechne alle h(v) und benutze
dabei Bellman-Ford
Algorithmus (h(v)=(s,v) ) .
w:ER
s
0
b
0
0
v
u
Graph
Dann kann man w(u,v) –Werte
nach der Formel
w(u,v) = w(u,v) + h(u) - h(v)
bekommen
Rekalibrierung
h : V  R heißt eine Rekalibrierung einen gerichteten Graphen G = (V , E)
mit Gewichtsfunktion w : V  R, falls ( u,v)  E : h(u) + w(u,v)  h(v) gilt .
Beobachtung.
Ist h eine Rekalibrierung , so ist w : E  R
mit (u,v)  E : w(u,v) : = w(u,v) + h(u) – h(v) eine nicht negative
Gewichtsfunktion.
Für w gilt zusätzlich : Ist p = (v0 ,..., vn) ein Weg, so ist
w(p)= k w(vi, vi+1) =  k (w(vi, vi+1) + h(vi) - h(vi+1) )
i=1
i=1
=  n w(vi, vi+1) + h(v1) - h(vn) = w(p) + h(v1) - h(vn) qed.
i=1
Falls p ein Kreis ist:
 n w(vi, vi+1) =  n (w(vi, vi+1) )
i=1
i=1
JOHNSON(G)
1 compute G  , where V [G ] = V [G]  {s} and
E[G'] = E[G]  {(s , v) : v  V [G]}, and w(s , v) = 0 for all v  V [G]
2 if BELLMAN-FORD(G  , w, s) = FALSE
3
then print “ Eingangsgraph hat einen negativen Zyklus”
4
else for each vertex v  V [G]
do set h(v) to (s, v) computed by BELLMAN-FORD
5
6
for each edge (u, v)  E[G ]
do w(u, v)  w(u, v) + h(u) − h(v)
7
8
for each vertex u  V [G]
9
do run DIJKSTRA(G, w , u) to compute
(u, v) for all v  V [G]
for each vertex v  V [G]
10
do duv  (u, v) + h(v) − h(u)
11
12
return D
Beispiel
(Johnson -Algorithmus für negative Gewichte)
B
2
3
4
8
A1
2
-4
1
7
5
E
6
4D
3C
-5
Beispiel
(Johnson -Algorithmus für negative Gewichte)
B
2
0
3
0
s
0 A1
0
4
8
0
2
0
0
-1
-4
1
7
-4
E5
6
0
4D
-5 3C
-5
Beispiel
(Johnson - Algorithmus für negative Gewichte)
h( v ) =  ( s, v )
w( u , v ) = w( u , v ) + h( u ) - h( v )
2B
5
4
1
s
A 0
1
0
0
4
0
-1
0
13
-5
0
0
2
10
0
-4
E5
2
0
4D
3C
Beispiel
(Johnson -Algorithmus für negative Gewichte)
d(B) = (A, B) = 2
B
-1
4
A
d(C) = (A, C) = 2
0
10
13
0
2
-5
0
E
2
d(E) = (A, E) = 0
0
0
-4
C
d(D) = (A, D) = 2
0
D
d(B) = (A, B) + h(B) − h(A) = 1
d(C) = (A, C) + h(C) − h(A) = - 3
d(D) = (A, D) + h(D) − h(A) = 2
d(E) = (A, E) + h(E) − h(A) = - 4
Beispiel
(Johnson -Algorithmus für negative Gewichte)
d(A) = (B, A) = 2
B
-1
4
A
d(C) = (B, C) = 0
0
10
13
0
0
2
0
-4
E
-5
2
0
C
d(D) = (B,D) = 0
d(E) = (B, E) = 2
d(A) = (B, A) + h(A) − h(B) = 3
d(C) = (B, C) + h(C) − h(B)= -4
0
D
d(D) = (B, D) + h(D)− h(B) = 1
d(E) = (B, E) + h(E) − h(B)= -1
Beispiel
(Johnson -Algorithmus für negative Gewichte)
d(A) = (C, A) = 2
B
-1
4
A
d(B) = (C, B) = 0
0
10
13
0
-5
0
2
0
0
-4
E
2
C
d(D) = (C, D) = 0
d(E) = (C, E) = 2
d(A) = (C, A) + h(A) − h(C) = 7
d(B) = (C, B) + h(B) − h(C) = 4
0
D
d(D) = (C,D) + h(D) − h(C) = 5
d(E) = (C, E) + h(E) − h(C) = 3
Beispiel
(Johnson -Algorithmus für negative Gewichte)
d(A) = (D, A) = 2
B
-1
4
A
d(B) = (D, B) = 0
0
10
13
0
2
-5
0
0
0
-4
E
2
C
d(C) = (D, C) = 0
d(E) = (D, E) = 2
d(A) = (D, A) + h(A) − h(D) = 2
d(B) = (D, B) + h(B) − h(D) = -1
0
D
d(C) = (D, C) + h(C) − h(D) = -5
d(E) = (D, E) + h(E) − h(D) = -2
Beispiel
(Johnson -Algorithmus für negative Gewichte)
d(A) = (E, A) = 4
B
-1
4
A
d(B) = (E, B) = 2
0
10
13
0
-5
0
2
E
2
d(D) = (E, D) = 2
0
0
-4
C
d(C) = (E, C) = 2
d(A) = (E, A) + h(A) − h(E) = 8
0
D
d(B) = (E, B) + h(B) − h(E) = 5
d(C) = (E, C) + h(C) − h(E) = 1
d(D) = (E, D) + h(D) − h(E) = 6
Komplexität des Johnson -Algorithmus
• Die Initialisierung besteht aus Q (|V|) Schritten
• Prüfung auf Existenz negativer Zyklen mit Bellman-Ford-Algorithmus
O (|VE|) Schritten
• Rekalibrierung Q (|E|)
• Dijkstradurchlauf O (|VE|)
• Distanzberechnung Q(|V|²)
Die Gesamtkomplexität des Johnson-Algorithmus beträgt
O (|V|²lg|V| + |V||E|lg|V|)
Herunterladen