Erinnerung VL 20.06.2016 I Graphtraversierung (DFS, topologische Sortierung und mehr) I Kürzeste Wege: Problemstellung, Algorithmen I Analoger Algorithmus I Dijkstras Algorithmus: Idee, Korrektheit I Heute: mehr zu Dijkstra, (Bellman-Ford) KIT Institut für Theoretische Informatik 1 I . . . doch zunächst KIT Institut für Theoretische Informatik 2 Feedback Vorlesungsbefragung I Vielen Dank für die zahlreichen Kommentare! I Wiederkehrende Kommentare: I Im Hörsaal zu laut, Mikro zu leise, bärtiger Dozent war netter I Zu langsam, zu schnell, langweilig, zu viele Anforderungen Gut: wenige Folien, schlecht: wenige Folien, zu voll I Mehr Beispiele/Bilder, Pseudocode in Monospace KIT Institut für Theoretische Informatik 3 Erinnerung: analoger Algorithmus M 0 Distance to M R 5 Lösung ohne Rechner: I Kanten → Fäden I Kantengewicht L Q Fadenlänge I Knoten → Knoten I Dann: Am Startknoten anheben. 11 13 15 O → H G N F K P E C 17 17 18 19 20 S V J W KIT Institut für Theoretische Informatik 4 Dijkstra: Implementierung? initialize d, parent all nodes are non-scanned ∃ 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 while Wichtigste Operation: nde u KIT Institut für Theoretische Informatik 5 Prioritätsliste Wir speichern ungescannte erreichte Knoten in adressierbarer Prioritätsliste Schlüssel ist Q. d[v ]. Knoten speichern handles. oder gleich items KIT Institut für Theoretische Informatik 6 Implementierung ≈ BFS mit PQ statt FIFO Function Dijkstra(s : NodeId) : NodeArray×NodeArray // returns (d, parent) Initialisierung: d=h∞, . . . , ∞i : NodeArray of R ∪ {∞} // parent=h⊥, . . . , ⊥i parent[s]:= : NodeArray tentative distance from root of NodeId s Q : NodePQ d[s] := 0; Q .insert(s) // // self-loop signals root unscanned reached nodes KIT Institut für Theoretische Informatik 7 : 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 ) ∈ E do if d[u] + c(e) < d[v ] then d[v ]:= d[u] + c(e) parent[v ] := u // if v ∈ Q then Q .decreaseKey(v ) else Q .insert(v ) return (d, parent) Function Dijkstra(s s u scanned // relax update tree u v reached KIT Institut für Theoretische Informatik 8 Beispiel Operation 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 deleteMin relax relax 7 2 3 5 2 a c b 2 9 5 s 10 8 1 0 f e 4 d 6 0 6 7 2 3 5 7 2 a c b 2 9 5 s 10 8 1 0 e f 4 d 10 0 6 7 2 3 5 7 2 a b c 2 9 s 10 5 1 8 0 f e 4 d 6 0 6 7 2 3 relax 2 relax relax 9 relax (e, 6) e →b 8 e →c 0 e →d deleteMin relax (b, 5) b→c 1 b→e deleteMin relax (a, 2) a→b deleteMin relax (s, 0) s →a 10 s →d deleteMin relax 2 3 5 2 a b c 2 9 5 s 10 8 1 0 e f 4 d 7 10 0 Queue (s) insert 4 (d, 6) d →s 5 d →b deleteMin (c, 7) 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) 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 KIT Institut für Theoretische Informatik 9 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) KIT Institut für Theoretische Informatik 10 Dijkstra: Laufzeit : 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 ) ∈ E do if d[u] + c(e) < d[v ] then d[v ]:= d[u] + c(e) parent[v ] := u if v ∈ Q then Q .decreaseKey(v ) else Q .insert(v ) return (d, parent) Function Dijkstra(s // O(n) ≤ n× ≤ m× // ≤ m× // ≤ m× // ≤ m× // ≤ m× // ≤ n× // // KIT Institut für Theoretische Informatik 11 Dijkstra: Laufzeit : 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 ) ∈ E do if d[u] + c(e) < d[v ] then d[v ]:= d[u] + c(e) parent[v ] := u if v ∈ Q then Q .decreaseKey(v ) else Q .insert(v ) return (d, parent) Function Dijkstra(s // O(n) ≤ n× ≤ m× // ≤ m× // ≤ m× // ≤ m× // ≤ m× // ≤ n× // // Insgesamt: TDijkstra = O m · TdecreaseKey (n) + n · (TdeleteMin (n) + Tinsert (n)) KIT Institut für Theoretische Informatik 11 Laufzeit Dijkstras ursprüngliche Implementierung: naiv I insert: O(1) I decreaseKey: I deleteMin: d[v ]:= d[u] + c(u, v ) O(1) O(n) d[v ]:= d[u] + c(u, v ) d komplett durchsuchen TDijkstra = O m · TdecreaseKey (n) + n · (TdeleteMin (n) + Tinsert (n)) TDijkstra59 = O(m · 1 + n · (n + 1)) = O m + n2 KIT Institut für Theoretische Informatik 12 Laufzeit Bessere Implementierung mit Binary-Heap-Prioritätslisten: I insert: O(log n) I decreaseKey: I deleteMin: O(log n) 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) KIT Institut für Theoretische Informatik 13 Laufzeit (Noch) besser mit Fibonacci-Heapprioritätslisten: I insert: O(1) I decreaseKey: I deleteMin: O(1) (amortisiert) 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! KIT Institut für Theoretische Informatik 14 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 KIT Institut für Theoretische Informatik 15 Monotone ganzzahlige Prioritätslisten Beobachtung: In Dijkstras Algorithmus steigt das Minimum in der Prioritätsliste monoton. Das kann man ausnutzen. u.U. bis herunter zu schnellere Algorithmen O(m + n). Details: in Algorithmen II KIT Institut für Theoretische Informatik 16 Negative Kosten Was machen wir, wenn es Kanten mit negativen Kosten gibt? Es kann Knoten geben mit s p u C q v s p d[v ] = −∞ (2) uC q v ... Wie nden wir heraus, welche das sind? Endlosschleifen vermeiden! KIT Institut für Theoretische Informatik 17 Zurück zu Basiskonzepten (Abschnitt 10.1 im Buch) Lemma: ∃ kürzester s v -Pfad P =⇒ P ist OBdA einfach (eng. simple) Beweisidee: (Kontraposition) Fall: ¬∃ s p v über negativen Kreis erreichbar kürzester u C ⇒ s v -Pfad (sondern beliebig viele q v ... q v s p (2) uC Sonst: betrachte beliebigen nicht-einfachen Alle Kreise streichen immer kürzere) s v -Pfad. einfacher, nicht längerer Pfad. KIT Institut für Theoretische Informatik 18 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 s 10 5 1 8 0 f d e 4 0 7 6 6 KIT Institut für Theoretische Informatik 19 Allgemeines Korrektheitskriterium t1 Sei tk t2 z }| { z }| { z }| { R = h· · · relax(e1 ) · · · relax(e2 ) · · · relax(ek ) · · ·i eine Folge von Relaxationsoperationen und p = he1 , e2 , . . . , ek i = hs, v1 , v2 , . . . , vk i Dann gilt anschlieÿend: ein kürzester Weg. d[vk ] = µ(vk ) Beweisskizze: (Eigentlich Induktion über d[s] = µ(s) k) bei Initialisierung d[v1 ] = µ(v1 ) nach Zeitpunkt t1 d[v2 ] = µ(v2 ) nach Zeitpunkt t2 nach Zeitpunkt tk ··· d[vk ] = µ(vk ) KIT Institut für Theoretische Informatik 20 Algorithmen brutal Bellman-Ford-Algorithmus für beliebige Kantengewichte Wir relaxieren alle Kanten (in irgendeiner Reihenfolge) Alle kürzeste Pfade in ⇒ G haben höchstens n−1 n−1 mal. Kanten. Jeder kürzeste Pfad ist eine Teilfolge dieser Relaxationen! v2 v=vk v3 s=v1 3. Runde 1. Runde (k−1). Runde 2. Runde KIT Institut für Theoretische Informatik 21 Negative Kreise nden Nach Ausführung von Bellman-Ford: ∀ negativen Kreise C: ∃(u, v ) ∈ C : d[u] + c(e) < d[v ] Beweis: Übung v und alle von v erreichbaren Knoten x haben µ(x) = −∞ KIT Institut für Theoretische Informatik 22 Beispiel KIT Institut für Theoretische Informatik 23