(Programmierpraktikum - Das Canadian Traveller Problem)

Werbung
Programmierpraktikum
Das Canadian Traveller Problem
Buckets
Rainer Schrader
Birgit Engels
Anna Schulze
Zentrum für Angewandte Informatik Köln
19. April 2006
1 / 20
2 / 20
Kürzeste Wege in Graphen
Buckets
Dijkstra-Algorithmus
Lemma
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.
(1) Dist (s) := 0, U = {s}
(2) for v ∈ V \{s} do
(3)
Beweis:
Dist (v ) = +∞, Vor (v ) = Null
(4) endfor
• Induktion über die while-Schleife.
• Mit dk , distk , Uk werden die entsprechenden Größen vor Ausführung der
(5) while U 6= ∅
(6)
choose u ∈ U with Dist (u) minimal (finde Min)
(7)
U := U \ {u} (lösche Min)
(8)
for all (u, v ) ∈ E
(9)
Dist (v ) = Dist (u) + c(u, v ), Vor (v ) = u, (verringere)
(11)
U := U ∪ {v } (füge ein)
(13)
•
•
•
•
if Dist (u) + c(u, v ) < Dist (v ) then
(10)
(12)
k-ten Iteration bezeichnet.
endif
endfor
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 , dass
distk (v ) ≤ distk −1 (v ) ≤ dk −1 + C ≤ dk + C.
• Ist v ∈
/ Uk −1 , so ist distk (v ) = dk + c(u, v ) ≤ dk + C.
(14) endwhile
3 / 20
2
4 / 20
Buckets
Buckets
• 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
• Die Menge U wird in C + 1 doppelt verketteten Listen Eimer(0), . . . ,
enthielt
Eimer(C) verwaltet.
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((i0 + i ) mod (C + 1)).
endif
• Die Liste Eimer (k ) enthält alle Knoten v ∈ U , für die gilt
k = dist (v ) mod (C + 1).
• Zusätzlich benutzen wir wieder einen Zeiger assign(v ),
er zeigt von v auf dasjenige Listenelement der Liste der Eimer, das v
enthält.
• Es gilt
Dist (v ) mod (C + 1) = i ⇔ v ∈ Eimer (i )
.
• Nach dem Lemma gilt, dass jeder Eimer in jeder Iteration nur Elemente
enthält, deren Dist -Werte gleich sind.
• 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 NewDist (v ) mod (C + 1) ein.
6 / 20
5 / 20
Buckets
Lemma
Die Laufzeit eines Dijkstra-Algorithmus, der die Front mit Hilfe von Buckets
verwaltet, beträgt O(n · |C| + m).
Beweis
Redistributive Heaps
• 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 + 1 mal durchlaufen also ist
Find Min in O(|C|) und die Behauptung folgt mit dem folgenden weiter
oben bewiesenem Lemma .
2
Lemma
Die Laufzeit des Dijkstra-Algorithmus ist
O(n · max{O(finde Min), O(lösche Min), O(füge ein)}) + m · O(verringere).
7 / 20
8 / 20
Redistributive Heaps
Redistributive Heaps
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
• Sei C = max{c(e) : e ∈ E } und k = 1 + dlog Ce.
• Im Unterschied zum vorigen Eimer-Verfahren, verwenden wir jetzt
Eimer, deren Größen sich dynamisch ändern.
• Weiter soll gelten:
• Die Inhalte der Eimer werden durch Listen contents(0), . . . , contents(k )
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 )| ≤ ij −1
=0 |range(j )| für i = 1, . . . , k
repräsentiert.
• Zusätzliche Zeiger assign(v ) zeigen auf dasjenige Listenelement des
Eimers, das den Knoten v repräsentiert.
• Die Knoten mit dist (v ) = ∞ verwalten wir in einem weiteren Eimer
Bk +1 , um in der Notation konsistent bleiben zu können.
9 / 20
10 / 20
Redistributive Heaps
Redistributive Heaps
• Lösche: lösche Knoten u aus der Liste assign(u) : lässt sich in O(1)
Schritten durchführen
• Verringere:
• Wir wählen am Anfang
range(0)
=
[0, 0]
range(i )
=
[2i −1 , 2i − 1] f ür alle i = 1, . . . , k
• 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.
d.h. range(1) = [1, 1], range(2) = [2, 3], range(3) = [4, 7] usw.
• Wiedereinfügen:
• was offensichtlich die obigen Bedingungen erfüllt.
• Die für die Implementation des Dijkstra-Verfahrens notwendigen
• 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ässt sich wie folgt ausführen:
procedure Wiedereinfügen
i = Eimer (assign(u))
contents(i ) = contents(i ) − {u}
while dist (u) ∈
/ range(i ) do i = i − 1
contents(i ) = contents(i ) ∪ {u}
Operationen können nun auf R−Heaps so realisiert werden:
11 / 20
12 / 20
Redistributive Heaps
Redistributive Heaps
Lemma
r Aufrufe der Prozedur Wiedereinfügen benötigen höchstens O(r + nk )
Schritte.
Beweis:
• Finde Min: Finde einen Knoten j mit minimaler Distanz dist (j )
• Jeder Aufruf benötigt O(1) Schritte und die Zeit, die die while-Schleife
verbraucht.
wie folgt:
• Bei jedem Schritt der while-Schleife wird aber der Zeiger des Eimers um
Suche den ersten nichtleeren Eimer Bp
Verteile den Inhalt von Bp auf die Eimer B0 , . . . , Bp
Gib den Inhalt von B0 zurück (bzw. von B1 , falls B0 = ∅).
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
Wir implementieren diese Idee in Form des folgenden Verfahrens:
• Füge ein:
• Wie bereits gesagt, sind alle Knoten mit Dist = ∞ in einem
zusätzlichen Eimer enthalten.
• Die Prozedur “Füge ein” muss dann dasselbe wie die Prozedur
“Verringere” leisten.
13 / 20
Redistributive Heaps
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
14 / 20
Redistributive Heaps
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).
15 / 20
16 / 20
Redistributive Heaps
Redistributive Heaps
Lemma
Es gilt stets [dmin , dmin + C] ⊆ [l0 , uk ].
Lemma
Die Prozeduren Lösche, Wiedereinfügen, und Finde Min führen R-Heaps in
R-Heaps über.
Beweis:
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.
•
•
•
•
0
Sei dazu dmin
∈ Bp das neue Minimum.
0
Es ist l00 = dmin
.
0
0
Ist p = k , so gilt uk0 = 2k − 1 + dmin
≥ dmin
+ 2C − 1.
Bei Finde Min bleiben die Eigenschaften 2 - 5 per Konstruktion erhalten.
Die Eigenschaft 1 ergibt sich aus dem obigen Lemma.
Wiedereinfügen lässt 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
Ist p < k , so gilt nach Eigenschaft 4,
0
0
uk − lk + 1 ≥ C, und somit uk ≥ C + lk − 1 ≥ C + dmin
, da dmin
∈
/ Bk .
• Damit folgt die Behauptung.
Lösche lässt offensichtlich die Bedingungen 1 - 5 invariant.
obigem Lemma.
2
• Damit haben nach Ausführung von Schritt 2 (Lösche) die Eimer
wiederum R-Heap-Struktur.
2
17 / 20
18 / 20
Redistributive Heaps
Redistributive Heaps
Satz
Das Dijkstra-Verfahren mit R-Heaps benötigt O(m + n log C) Schritte.
Lemma
Gilt in der Prozedur Finde Min p ≥ 2, so wird der Inhalt des Eimers Bp auf die
0
neuen Eimer B00 , . . . , Bp−1
verteilt, d.h. Bp0 = ∅.
Beweis:
Beweis:
• Lösche kann höchstens n-mal aufgerufen werden mit einer Laufzeit von
O(n).
• Wir zeigen, dass Bp0 = ∅.
(i) p < k :
•
•
•
•
• Wiedereinfügen wird höchstens m-mal aufgerufen, woraus sich eine
Laufzeit von O(m + nk ) ergibt.
0
Es ist up ≤ lp + 2p−1 − 1 < lp + 2p−1 ≤ dmin
+ 2p−1 .
0
p−1
0
Nach Konstruktion ist lp = 2
+ dmin und
0
} < lp0 .
up0 = min{up , 2p − 1 + dmin
Somit ist Bp0 = ∅.
• Finde Min wird höchstens n-mal benutzt.
• Jeder Aufruf benötigt höchstens O(k ) Schritte,
um einen ersten nichtleeren Eimer Bp zu finden,
und höchstens O(k ) Schritte, um die Eimer neu zu erzeugen.
(ii) p = k :
•
•
•
•
•
• Ist p ≥ 1, so werden zusätzlich noch O(|contents(p)|) viele Schritte für
0
0
Es ist Bk0 = [dmin
+ C, dmin
+ 2C − 1].
Das letzte Intervall war Bk = [lk , uk ], wobei
0
0
lk ≤ dmin
und uk ≤ lk + 2k −1 − 1 ≤ dmin
+ C − 1 = uk −1 .
0
Daraus folgt, dass Bk ⊆ [l0 , dmin + C − 1].
Somit werden alle Knoten aus Bk auf die Eimer B00 , . . . , Bk0 −1
verteilt und Bk0 ist leer.
2
die Minimumsuche in Bp durchgeführt.
• Da bei jedem Durchsuchen eines Eimers 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 ) =
19 / 20
O(m + n log C).
2
20 / 20
Herunterladen