-1.1 Wegeprobleme in Graphen

Werbung
Der Kruskal-Algorithmus ist ein Beispiel für die “greedy”-Strategie, weil er immer nur die lokal minimal kostende Kante zwischen zwei Knoten der Menge
hinzufügt. Die “greedy”-Strategie ist eine Entwurfsstrategie für Algorithmen,
bei der immer das lokal beste bearbeitet(hinzugefügt) wird.
-1.1
Wegeprobleme in Graphen
Situation: Gegeben sei ein gerichteter Graph G = (V, E), dessen Kanten mit
nichtnegativen reellen Zahlen R≥0 markiert sind, welche sich aus der Kostenfunktion c : E → R≥0 ergeben.
Die Kanten können auf zwei Arten dargestellt werden:
1. Listendarstellung: Für jeden Knoten gibt es eine Liste der adjazenten Knoten mit jeweils auch Kosten der entsprechenden Kante.
2. Matrixdarstellung: Die Listen sind zu einer n × n-Matrix mit Einträgen
∈ R≥0 ∪ {∞} (“∞”, wenn keine Kante zwischen i und j existiert, also
(i, j) ∈
/ E)
Problem -1.1.1. Wir betrachten nun folgende Probleme:
a) geg: Knoten u, v
finde: kürzesten Weg von u nach v, d.h. die Summe aller Kanten ist minimal (Beispiel: Routenplanung)
b) SSSP - “single source shortest paths”
geg: Knoten s
finde: Länge aller kürzesten Wege von s nach allen anderen Knoten
c) APSP - “all pairs shortest paths”
geg: u, v ∈ V
finde: für alle Paare u, v den kürzesten Weg von u nach v
Anmerkung: Ein Algorithmus der eins dieser Probleme löst, löst automatisch
die vorhergehenden Probleme. Allerdings ist kein schnellerer Algorithmus für a)
bekannt, als b) zu lösen.
-1.1.1
SSSP & Dijkstras Algorithmus
Idee: Es wird eine Menge S aufrecht erhalten, welche jene Knoten enthält, zu
denen bereits der kürzeste Weg (ausgehend von s) gefunden wurde. Initialisiert
wird die Menge mit S = {s}. Wir definieren dazu ein Feld D, welches mit D [v]
die Länge des kürzesten Weges von s nach v angibt, der nur Zwischenknoten
∈ S verwendet.
1
Algorithmus von Dijkstra:
1
2
3
4
5
6
7
S := {s} D [s] := 0;
für alle Knoten v 6= s: D [v] := C (s, v);
while V \ S 6= ∅ do
wähle den Knoten w ∈ V \ S mit minimalem D [w];
S := S ∪ {w};
for each u ∈ V \ S, u adjazent zu w do
D [u] := min (D [u] , D [w] + C (w, u))
Algorithm 1: Dijkstra
i
0
1
2
3
D [v1 ]
0
0
0
0
D [v2 ]
2
2
2
2
D [v3 ]
∞
5
5
5
D [v4 ]
∞
∞
9
9
D [v5 ]
10
9
9
9
S
{1, 2}
{1, 2, 3}
{1, 2, 3, 4}
{1, 2, 3, 4, 5}
Korrektheit von Dijkstra
Behauptung -1.1.2. Zu jeder Zeit gilt, dass zu jedem Knoten v in S D[v]
gleich der Länge des kürzesten Weges von s nach v ist.
Beweis. Induktion über die Anzahl k der Iterationen der Schleife (3)-(6)
Induktionsanfang:
Sei d(v) = Länge des kürzesten Weges von s nach v,k = 0. Es ist S = {s} und
D[s] = 0
Induktionsschritt: k → k + 1
Sei w der Knoten, der in der (k + 1)-ten Iteration zu S kommt. Angenommen,
die Behauptung sei falsch für w, also D[w] > d[w] (denn D[w] ist die Länge
eines Weges von s nach w). Betrachte den kürzesten Weg π von s nach w. (u, v)
sei die Kante auf π, die als erste aus Sk herausführt, wobei Sk = S nach k
Iterationen. Dann ist nach Induktionsvoraussetzung d[u] = D[u]
d(v) = d(u) + c(u, v), wobei c(v,u) die Kosten der Kanten von u nach v sind
2
d(v) = d(u) + c(u, v) = D[u] + c(u, v) ≤ D[v], denn beim Einfügen von u in
S wurde D[v] mit D[u] + c(u, v) verglichen und auf das Minimum von beiden gesetzt(Zeile 6). Also ist d(v) ≤ D[v] ⇒ d(v) = D[v]. Andererseits ist
D[w] ≥ d(w) ≥ d(v) = D[v]. Dies ist ein Widerspruch zu Zeile 4 des DijkstraAlgorithmus, denn dort wäre v ausgewählt worden.
Datenstrukturen und Laufzeit Für Knoten V \S brauchen wir eine Prioritätswarteschlange. Hierfür bietet sich ein “Heap” an.
Die Initialisierung in Zeile 2 ist in O(n) Zeit möglich. Das “Minimum streichen” in Zeile 4 braucht jeweils O(log n) Zeit, den “Wert vermindern” in Zeile
6 braucht jeweils O(log n) Zeit, 6 wird m-mal ausgeführt , wobei m = Anzahl
der Kanten.
Also kommt man insgesamt auf O( n log n + m log n) = O((m + n) log n).
| {z } | {z }
Zeilen2,4
Zeile6
Satz -1.1.3. Der Algorithmus von Dijkstra berechnet die Längen aller kürzesten
Wege eines gerichteten, markierten Graphen mit n Knoten und m Kanten in
O((m + n) log n) Zeit. Also höchstens O(n2 log n)
-1.1.2
Kürzeste Wege zwischen allen Knotenpaaren
Man könnte n-mal Dijkstra ausführen. Dadurch würde sich eine Laufzeit von
O((nm + n2 ) log n) = O(n3 log n) ergeben.
Algorithmus von Floyd-Warshall
(k)
Die Knotenmenge sei o.B.d.A V = {1, ..., n}. Wir definieren Pij = Menge aller
(k)
Wege von i nach j mit Zwischenknoten ∈ {1, ..., k}, dij = Länge des kürzesten
(k)
Weges in Pij , wobei 1 ≤ i, j ≤ n 0 ≤ k ≤ n
Dann gilt für i 6= j:
c(i, j) if (i, j) ∈ E;
(k)
dij =
∞
sonst.
3
Herunterladen