Dijkstras Algorithmus: Pseudocode

Werbung
Dijkstras Algorithmus: Pseudocode
initialize d, parent
all nodes are non-scanned
while 9 non-scanned node u with d[u] < •
u := non-scanned node v with minimal d[v ]
relax all edges (u, v ) out of u
u is scanned now
Behauptung: Am Ende definiert d die optimalen Entfernungen
und parent die zugehörigen Wege
361
Beispiel
2 3
2
b
c
a
2
9
5
s
10
8
1
0
e
f
4 d
0
7
10
2 3 5
7
2
a
b
c
2
9
5
s
10
8
1
0
e
f
4 d
0
7
6
6
2 3 5
2
a
b
c
2
9
5
s
10
8
1
0
e
f
4 d
0
7
10
7
2 3 5
2
a
c
b
2
9
5
s
10
8
1
0
f
e
4 d
0
7
6
6
2 3 5
7
2
a
c
b
2
9
5
s
10
8
1
0
e
f
4 d
0
10
6 7
2 3 5
7
2
a
b
c
2
9
5
s
10
8
1
0
f
e
4 d
0
6
6 7
362
Korrektheit
Annahme: alle Kosten nicht-negativ!
Wir zeigen: 8v 2 V :
I
v erreichbar =) v wird irgendwann gescannt
I
v gescannt =) µ(v ) = d[v ]
363
v erreichbar =) v wird irgendwann gescannt
Annahme: v ist erreichbar, aber wird nicht gescannt
z
s = v1
|
gescannt
ungescannt
ungescannt
}|
{
z}|{
z }| {
! v1 ! · · · ! vi 1 ! vi ! · · · ! 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
?
364
v erreichbar =) v wird irgendwann gescannt
Annahme: v ist erreichbar, aber wird nicht gescannt
z
s = v1
|
gescannt
ungescannt
ungescannt
}|
{
z}|{
z }| {
! v1 ! · · · ! vi 1 ! vi ! · · · ! 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 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
z
s = v1
|
Scan-Zeit t
Scan-Zeit < t
Scan-Zeit = t
}|
{
z}|{
z }| {
! v1 ! · · · ! vi 1 ! vi ! · · · !
vk = v
{z
}
ein kürzester s–v Pfad
Also gilt zur Zeit t:
µ(vi
1)
= d[vi
1]
vi 1 ! vi wurde relaxiert
z}|{
=) 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.
365
Implementierung?
initialize d, parent
all nodes are non-scanned
while 9 non-scanned node u with d[u] < •
u := non-scanned node v with minimal d[v ]
relax all edges (u, v ) out of u
u is scanned now
Wichtigste Operation: finde u
366
Prioritätsliste
Wir speichern ungescannte erreichte Knoten in
addressierbarer Prioritätsliste Q.
Schlüssel ist d[v ].
Knoten speichern handles.
oder gleich items
367
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 root
parent=h?, . . . , ?i : NodeArray of NodeId
parent[s]:= s
// self-loop signals root
Q : NodePQ
// unscanned reached nodes
d[s] := 0; Q.insert(s)
368
Function Dijkstra(s : NodeId) : NodeArray⇥NodeArray
d = h•, . . . , •i; parent[s]:= s; d[s] := 0; Q.insert(s)
while Q 6= 0/ do
u := Q.deleteMin
// scan u
foreach edge e = (u, v ) 2 E do
if d[u] + c(e) < d[v ] then
d[v ]:= d[u] + c(e)
parent[v ] := u
//
if v 2 Q then Q.decreaseKey(v )
else Q.insert(v )
return (d, parent)
s
u
scanned
// relax
update tree
u
v
reached
369
Beispiel
2 3
2
b
c
a
2
9
5
s
10
8
1
0
e
f
4 d
0
7
10
2 3 5
7
2
a
b
c
2
9
5
s
10
8
1
0
e
f
4 d
0
7
6
6
2 3 5
2
a
b
c
2
9
5
s
10
8
1
0
e
f
4 d
0
7
10
7
2 3 5
2
a
c
b
2
9
5
s
10
8
1
0
f
e
4 d
0
7
6
6
2 3 5
7
2
a
c
b
2
9
5
s
10
8
1
0
e
f
4 d
0
7
10
6
2 3 5
7
2
a
b
c
2
9
5
s
10
8
1
0
f
e
4 d
0
7
6
6
Operation
insert(s)
deleteMin
2
relax s ! a
10
relax s ! d
deleteMin
3
relax a ! b
deleteMin
2
relax b ! c
1
relax b ! e
deleteMin
9
relax e ! b
8
relax e ! c
0
relax e ! d
deleteMin
4
relax d ! s
5
relax d ! b
deleteMin
(s, 0)
(a, 2)
(b, 5)
(e, 6)
(d, 6)
(c, 7)
Queue
h(s, 0)i
hi
h(a, 2)i
h(a, 2), (d, 10)i
h(d, 10)i
h(b, 5), (d, 10)i
h(d, 10)i
h(c, 7), (d, 10)i
h(e, 6), (c, 7), (d, 10)i
h(c, 7), (d, 10)i
h(c, 7), (d, 10)i
h(c, 7), (d, 10)i
h(d, 6), (c, 7)i
h(c, 7)i
h(c, 7)i
h(c, 7)i
hi
370
Dijkstra: Laufzeit
Function Dijkstra(s : NodeId) : NodeArray⇥NodeArray
Initialisierung:
d=h•, . . . , •i : NodeArray of R [ {•}
// O(n)
parent=h?, . . . , ?i : NodeArray of NodeId
// O(n)
parent[s]:= s
Q : NodePQ
// unscanned reached nodes, O(n)
d[s] := 0; Q.insert(s)
371
Dijkstra: Laufzeit
Function Dijkstra(s : NodeId) : NodeArray⇥NodeArray
d = {•, . . . , •}; parent[s]:= s; d[s] := 0; Q.insert(s)
while Q 6= 0/ do
u := Q.deleteMin
foreach edge e = (u, v ) 2 E do
if d[u] + c(e) < d[v ] then
d[v ]:= d[u] + c(e)
parent[v ] := u
if v 2 Q then Q.decreaseKey(v )
else Q.insert(v )
return (d, parent)
// O(n)
//  n⇥
//  m⇥
//  m⇥
//  m⇥
//  m⇥
//  m⇥
//  n⇥
372
Dijkstra: Laufzeit
Function Dijkstra(s : NodeId) : NodeArray⇥NodeArray
d = {•, . . . , •}; parent[s]:= s; d[s] := 0; Q.insert(s)
while Q 6= 0/ do
u := Q.deleteMin
foreach edge e = (u, v ) 2 E do
if d[u] + c(e) < d[v ] then
d[v ]:= d[u] + c(e)
parent[v ] := u
if v 2 Q then Q.decreaseKey(v )
else Q.insert(v )
return (d, parent)
// O(n)
//  n⇥
//  m⇥
//  m⇥
//  m⇥
//  m⇥
//  m⇥
//  n⇥
Insgesamt:
TDijkstra = O m · TdecreaseKey (n) + n · (TdeleteMin (n) + Tinsert (n))
372
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
373
Laufzeit
Bessere Implementierung mit Binary-Heap-Prioritätslisten:
I
insert: O(log n)
I
decreaseKey: O(log n)
I
deleteMin: O(log n)
TDijkstra = O m · TdecreaseKey (n) + n · (TdeleteMin (n) + Tinsert (n))
TDijkstraBHp = O(m · log n + n · (log n + log n))
= O((m + n) log n)
374
Laufzeit
(Noch) besser mit Fibonacci-Heapprioritätslisten:
I
insert: O(1)
I
decreaseKey: O(1) (amortisiert)
I
deleteMin: O(log n) (amortisiert)
TDijkstra = O m · TdecreaseKey (n) + n · (TdeleteMin (n) + Tinsert (n))
TDijkstraFib = O(m · 1 + n · (log n + 1))
= O(m + n log n)
Aber: konstante Faktoren in O(·) sind hier größer!
375
Analyse im Mittel
Modell: Kantengewichte sind „zufällig“ auf die Kanten verteilt
Dann gilt:
⇣
m⌘
E[TDijkstraBH(ea)p ] = O m + n log n log
n
Beweis: In Algorithmen II
376
Monotone ganzzahlige Prioritätslisten
Beobachtung: In Dijkstras Algorithmus steigt das Minimum in der
Prioritätsliste monoton.
Das kann man ausnutzen.
schnellere Algorithmen
u.U. bis herunter zu O(m + n).
Details: in Algorithmen II
377
Negative Kosten
Was machen wir, wenn es Kanten mit negativen Kosten gibt?
Es kann Knoten geben mit d[v ] = •
s p
u C
q v
s p
uC
(2)
q v ...
Wie finden wir heraus, welche das sind?
Endlosschleifen vermeiden!
a
b
d
42
0
−00
−00
−00
0
+00−2 −00
j
k
0
−1
0
s
f
2
2
g
5
−3
−2
−1
−3
−1 i −2 h
378
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)
q v s p
q v ...
s p
(2)
u C
uC
Sonst: betrachte beliebigen nicht-einfachen s–v -Pfad.
Alle Kreise streichen
einfacher, nicht längerer Pfad.
a
b
d
42
0
−00
−00
−00
0
+00−2 −00
j
k
0
−1
0
s
f
2
2
g
5
−3
−2
−1
−3
−1 i −2 h
379
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-Baum
Alle kürzeste Pfade von s aus zusammen bilden einen Baum, falls es
keine negativen Kreise gibt.
2 3 5
7
2
a
b
c
2
9
5
s
10
8
1
0
f
e
4 d
6 0 6 7
380
Herunterladen