Post on 20-Aug-2019
361
Dijkstras Algorithmus: Pseudocode
initialize d , parentall nodes are non-scannedwhile 9 non-scanned node u with d [u]< •
u := non-scanned node v with minimal d [v ]relax all edges (u,v) out of uu is scanned now
Behauptung: Am Ende definiert d die optimalen Entfernungenund parent die zugehörigen Wege
362
Beispiel
cb
d e f
s
cb
d e f
s
2
1
9
3 2
8
70
5
010
2
4
a5
10
c
d e f
s
b
f
s
b
ed
c
c
fed
c
d f
b
e
2
1
9
3 2
8
70
5
010
2
4
a5
6 6
7
2
1
9
3 2
8
70
5
010
2
4
a5
6 6
7
s
b
2
1
9
3 2
8
70
5
010
2
4
a5
6 6
7
s1
9
3 2
8
70
5
010
2
4
a
10
2
2
1
9
3 2
8
70
5
010
2
4
a5
10 6
7
363
Korrektheit Annahme: alle Kosten nicht-negativ!
Wir zeigen: 8v 2 V :
I v erreichbar =) v wird irgendwann gescanntI v gescannt =) µ(v) = d [v ]
364
v erreichbar =) v wird irgendwann gescannt
Annahme: v ist erreichbar, aber wird nicht gescannt
gescanntz }| {
s = v1 �! v1 �! · · ·�! vi�1 �!ungescannt
z}|{
vi �! · · ·�!ungescanntz }| {
vk = v| {z }
ein kürzester s–v Pfad
=) vi�1 wird gescannt=) Kante vi�1 �! vi wird relaxiert=) d [vi ]< •Widerspruch – nur Knoten x mit d [x ] = • werden nie gescannt ?
Ups: Spezialfall i = 1?Kann auch nicht sein.v1 = s wird nach Initialisierung gescannt.
364
v erreichbar =) v wird irgendwann gescannt
Annahme: v ist erreichbar, aber wird nicht gescannt
gescanntz }| {
s = v1 �! v1 �! · · ·�! vi�1 �!ungescannt
z}|{
vi �! · · ·�!ungescanntz }| {
vk = v| {z }
ein kürzester s–v Pfad
=) vi�1 wird gescannt=) Kante vi�1 �! vi wird relaxiert=) d [vi ]< •Widerspruch – nur Knoten x mit d [x ] = • werden nie gescannt
Ups: Spezialfall i = 1?Kann auch nicht sein.v1 = s wird nach Initialisierung gescannt.
365
v gescannt =) µ(v) = d [v ]
Annahme: v gescannt und µ(v)< d [v ]OBdA: v ist der erste gescannte Knoten mit µ(v)< d [v ].t := Scan-Zeit von v
Scan-Zeit < tz }| {
s = v1 �! v1 �! · · ·�! vi�1 �!Scan-Zeit � t
z}|{
vi �! · · ·�!Scan-Zeit = t
z }| {
vk = v| {z }
ein kürzester s–v Pfad
Also gilt zur Zeit t:
µ(vi�1) = d [vi�1]
vi�1 ! vi wurde relaxiertz}|{
=) d [vi ] d [vi�1]+ c(vi�1,vi ) = µ(vi ) µ(v)< d [v ]=) vi wird vor v gescannt. Widerspruch!
Wieder: Spezialfall i = 1 unmöglich.
366
Implementierung?
initialize d , parentall nodes are non-scannedwhile 9 non-scanned node u with d [u]< •
u := non-scanned node v with minimal d [v ]relax all edges (u,v) out of uu is scanned now
Wichtigste Operation: finde u
367
Prioritätsliste
Wir speichern ungescannte erreichte Knoten inaddressierbarer Prioritätsliste Q.
Schlüssel ist d [v ].
Knoten speichern handles. oder gleich items
368
Implementierung ⇡ BFS mit PQ statt FIFO
Function Dijkstra(s : NodeId) : NodeArray⇥NodeArray// returns (d ,parent)
Initialisierung:d=h•, . . . ,•i : NodeArray of R[{•}
// tentative distance from rootparent=h?, . . . ,?i : NodeArray of NodeIdparent[s]:= s // self-loop signals rootQ : NodePQ // unscanned reached nodesd [s] := 0; Q.insert(s)
369
Function Dijkstra(s : NodeId) : NodeArray⇥NodeArrayd = h•, . . . ,•i; parent[s]:= s; d [s] := 0; Q.insert(s)while Q 6= /0 do
u := Q.deleteMin// scan u
s
scanned
u
foreach edge e = (u,v) 2 E doif d [u]+ c(e)< d [v ] then // relax
d [v ]:= d [u]+ c(e)parent[v ] := u // update treeif v 2 Q then Q.decreaseKey(v)else Q.insert(v)
u v
reachedreturn (d ,parent)
370
Beispiel
cb
d e f
s
cb
d e f
s
2
1
9
3 2
8
70
5
010
2
4
a5
10
c
d e f
s
b
f
s
b
ed
c
c
fed
c
d f
b
e
2
1
9
3 2
8
70
5
010
2
4
a5
6 6
7
2
1
9
3 2
8
70
5
010
2
4
a5
6 6
7
s
b
2
1
9
3 2
8
70
5
010
2
4
a5
6 6
7
s1
9
3 2
8
70
5
010
2
4
a
10
2
2
1
9
3 2
8
70
5
010
2
4
a5
10 6
7
Operation Queueinsert(s) h(s,0)ideleteMin (s,0) hirelax s
2! a h(a,2)irelax s
10! d h(a,2),(d ,10)ideleteMin (a,2) h(d ,10)irelax a
3! b h(b,5),(d ,10)ideleteMin (b,5) h(d ,10)irelax b
2! c h(c ,7),(d ,10)irelax b
1! e h(e,6),(c ,7),(d ,10)ideleteMin (e,6) h(c ,7),(d ,10)irelax e
9! b h(c ,7),(d ,10)irelax e
8! c h(c ,7),(d ,10)irelax e
0! d h(d ,6),(c ,7)ideleteMin (d ,6) h(c ,7)irelax d
4! s h(c ,7)irelax d
5! b h(c ,7)ideleteMin (c ,7) hi
371
Dijkstra: Laufzeit
Function Dijkstra(s : NodeId) : NodeArray⇥NodeArrayInitialisierung:
d=h•, . . . ,•i : NodeArray of R[{•} // O(n)parent=h?, . . . ,?i : NodeArray of NodeId // O(n)parent[s]:= sQ : NodePQ // unscanned reached nodes, O(n)d [s] := 0; Q.insert(s)
372
Dijkstra: Laufzeit
Function Dijkstra(s : NodeId) : NodeArray⇥NodeArrayd = {•, . . . ,•}; parent[s]:= s; d [s] := 0; Q.insert(s) // O(n)while Q 6= /0 do
u := Q.deleteMin // n⇥foreach edge e = (u,v) 2 E do // m⇥
if d [u]+ c(e)< d [v ] then // m⇥d [v ]:= d [u]+ c(e) // m⇥parent[v ] := u // m⇥if v 2 Q then Q.decreaseKey(v) // m⇥else Q.insert(v) // n⇥
return (d ,parent)
Insgesamt:
TDijkstra = O�
m ·TdecreaseKey(n)+n · (TdeleteMin(n)+Tinsert(n))�
372
Dijkstra: Laufzeit
Function Dijkstra(s : NodeId) : NodeArray⇥NodeArrayd = {•, . . . ,•}; parent[s]:= s; d [s] := 0; Q.insert(s) // O(n)while Q 6= /0 do
u := Q.deleteMin // n⇥foreach edge e = (u,v) 2 E do // m⇥
if d [u]+ c(e)< d [v ] then // m⇥d [v ]:= d [u]+ c(e) // m⇥parent[v ] := u // m⇥if v 2 Q then Q.decreaseKey(v) // m⇥else Q.insert(v) // n⇥
return (d ,parent)
Insgesamt:
TDijkstra = O�
m ·TdecreaseKey(n)+n · (TdeleteMin(n)+Tinsert(n))�
373
Laufzeit
Dijkstras ursprüngliche Implementierung: „naiv“I insert: O(1) d [v ]:= d [u]+ c(u,v)
I decreaseKey: O(1) d [v ]:= d [u]+ c(u,v)
I deleteMin: O(n) d komplett durchsuchen
TDijkstra = O�
m ·TdecreaseKey(n)+n · (TdeleteMin(n)+Tinsert(n))�
TDijkstra59 = O(m ·1+n · (n+1))= O
�
m+n2�
374
Laufzeit
Bessere Implementierung mit Binary-Heap-Prioritätslisten:I insert: O(logn)I decreaseKey: O(logn)I deleteMin: O(logn)
TDijkstra = O�
m ·TdecreaseKey(n)+n · (TdeleteMin(n)+Tinsert(n))�
TDijkstraBHp = O(m · logn+n · (logn+ logn))= O((m+n) logn)
375
Laufzeit
(Noch) besser mit Fibonacci-Heapprioritätslisten:I insert: O(1)I decreaseKey: O(1) (amortisiert)I deleteMin: O(logn) (amortisiert)
TDijkstra = O�
m ·TdecreaseKey(n)+n · (TdeleteMin(n)+Tinsert(n))�
TDijkstraFib = O(m ·1+n · (logn+1))= O(m+n logn)
Aber: konstante Faktoren in O(·) sind hier größer!
376
Analyse im Mittel
Modell: Kantengewichte sind „zufällig“ auf die Kanten verteiltDann gilt:
E[TDijkstraBH(ea)p] = O⇣
m+n logn logm
n
⌘
Beweis: In Algorithmen II
377
Monotone ganzzahlige Prioritätslisten
Beobachtung: In Dijkstras Algorithmus steigt das Minimum in derPrioritätsliste monoton.
Das kann man ausnutzen. schnellere Algorithmenu.U. bis herunter zu O(m+n).
Details: in Algorithmen II
378
Negative Kosten
Was machen wir, wenn es Kanten mit negativen Kosten gibt?Es kann Knoten geben mit d [v ] =�•
s p vq ...Cs p vq
C (2)u u
Wie finden wir heraus, welche das sind?Endlosschleifen vermeiden!
0
−1 −2
−22
50
−2
42
0
2 −3
−3−10−1
b d f
ijk hs
ga
+00 −00
−00−00 −00
379
Zurück zu Basiskonzepten (Abschnitt 10.1 im Buch)
Lemma: 9 kürzester s–v -Pfad P =) P ist OBdA einfach(eng. simple)Beweisidee: (Kontraposition)Fall: v über negativen Kreis erreichbar )¬9 kürzester s–v -Pfad (sondern beliebig viele immer kürzere)
s p vq ...Cs p vq
C (2)u u
Sonst: betrachte beliebigen nicht-einfachen s–v -Pfad.Alle Kreise streichen einfacher, nicht längerer Pfad.
0
−1 −2
−22
50
−2
42
0
2 −3
−3−10−1
b d f
ijk hs
ga
+00 −00
−00−00 −00
380
Mehr BasiskonzepteÜbung, zeige:
Teilpfade kürzester Pfade sind selbst kürzeste Pfade
a�b�c�d a�b,b�c ,c�d ,a�b�c ,b�c�d
Übung: Kürzeste-Wege-BaumAlle kürzeste Pfade von s aus zusammen bilden einen Baum, falls eskeine negativen Kreise gibt.
f
s
b
ed
c2
1
9
3 2
8
70
5
010
2
4
a5
6 6
7