Motivation Kap. 6.3: Traversieren von Graphen Kap. 6.4: Elementare Graphalgorithmen Heute braucht es keine Motivation, denn: Carsten Gutwenger Lehrstuhl für Algorithm Engineering, LS11 Spielereien Fakultät für Informatik, TU Dortmund DFS mit 18. VO DAP2 SS 2009 25. Juni 2009 Carsten Gutwenger DAP2 SS09 1 Carsten Gutwenger DAP2 SS09 2 Überblick Kap. 6.3.2 Tiefensuche • Traversieren von Graphen: – Breitensuche (BFS) – Tiefensuche (DFS) • Elementare Graphenalgorithmen: – Zusammenhangskomponenten – Kreise in Graphen – Topologisches Sortieren Carsten Gutwenger DAP2 SS09 3 Tiefensuche (DFS) 4 Methode: DFS-VISIT(v): • Durchlaufe alle Nachbarn von v • Für jeden neu entdeckten (nicht markierten) Knoten w: – Markiere w; – rufe DFS-VISIT(w) auf. Idee: besuche die Knoten rekursiv: wenn v zum ersten Mal gesehen wird, markiere ihn als gesehen und erforsche den Graphen von v aus weiter! • Im Gegensatz zur Breitensuche, wird hier der Graph erst einmal in seiner Tiefe durchdrungen. • Bei Breitensuche werden erst alle gesehenen Knoten bearbeitet, bevor die neuen bearbeitet werden (Queue). Hier wir immer erst das Neue erledigt. DAP2 SS09 DAP2 SS09 Tiefensuche DFS engl.: Depth-first-search, DFS Carsten Gutwenger Carsten Gutwenger • Der folgende Algorithmus DFS(G) durchwandert alle Knoten des Graphen. • Im Feld π[w] wird jeweils der Vorgänger von w (also v) gespeichert. 5 Carsten Gutwenger DAP2 SS09 6 1 Algorithmus DFS(G) Beispiel für DFS Sei G=(V,E) ungerichteter Graph, v,w: Knoten (1) for all v∈V do { marked[v]:=false; π[v]:=nil} (2) for all v∈V do (3) if not marked[v] then DFS-VISIT(v) 2 (4) procedur DFS-VISIT(Node v) (5) marked[v]:=true (6) for all w∈N(v) do (7) if not marked[w] then { (8) π[w]:=v (9) DFS-VISIT(w) (10) } Carsten Gutwenger c DAP2 SS09 7 Carsten Gutwenger Beispiel für DFS 2 g e c e c DAP2 SS09 2 3 3 Carsten Gutwenger 4 DAP2 SS09 10 Beispiel für DFS f g e c 4 5 Carsten Gutwenger 2 9 Beispiel für DFS f g e c 8 Beispiel für DFS 3 Carsten Gutwenger DAP2 SS09 DAP2 SS09 11 2 3 4 5 Carsten Gutwenger DAP2 SS09 12 2 Beispiel für DFS 2 g e c 3 Beispiel für DFS 4 5 Carsten Gutwenger DAP2 SS09 2 d e c 6 13 2 7 3 6 b d e c 4 DAP2 SS09 2 7 2 7 3 6 14 4 5 Carsten Gutwenger DAP2 SS09 16 Beispiel für DFS 4 2 e c 5 Carsten Gutwenger 3 6 15 Beispiel für DFS d e c DAP2 SS09 Beispiel für DFS 5 Carsten Gutwenger 4 5 Carsten Gutwenger Beispiel für DFS b d e c 3 DAP2 SS09 17 7 3 6 4 5 Carsten Gutwenger DAP2 SS09 18 3 Beispiel für DFS 2 c 3 4 6 7 Beispiel für DFS 2 5 Carsten Gutwenger 19 2 3 • DFS teilt die Kanten in T-Kanten und B-Kanten • Für jede B-Kante (u,v) gilt: Es gibt genau einen Weg von v nach u mit T-Kanten im DFS-Baum 5 7 Jeder Knoten erhält eine eindeutige DFS-Nummer. Für die Rückwärtskanten (u,v) gilt: DFSNUM(u) > DFSNUM(v). • • DFS teilt die Kanten in T-Kanten und B-Kanten Für jede B-Kante (u,v) gilt: Es gibt genau einen Weg von v nach u mit T-Kanten im DFS-Baum • • • • 4 • v 6 6 u 5 DAP2 SS09 22 Analyse von DFS • • 7 4 Carsten Gutwenger DFS-Baum 3 3 v Die orangen Kanten (diejenigen Kanten (u,v), die zum ersten Mal v besuchen) bilden einen Baum: den DFS-Baum (G zusammenhängend, sonst Wald) 2 20 DFS-Baum 2 Sei G zusammenhängend DAP2 SS09 DFS-Baum besteht aus • Baumkanten (tree edges, T-Kanten): (π(v),v) • Rückwärtskanten (back edges, B-Kanten): s.u. 4 6 7 5 Carsten Gutwenger Sei G zusammenhängend Beispiel für DFS 4 6 7 DAP2 SS09 3 Initialisierung: Θ(|V|) Die for-all-Schleife ohne Aufrufe von DFS-VISIT(): O(|V|). DFS-VISIT() wird für jeden Knoten genau einmal aufgerufen. Jeder Aufruf von DFS-VISIT(v) (ohne Kosten der rekursiven Aufrufe) benötigt Θ(d(v)) Zeit. Gesamtaufwand: Θ(|V|)+∑ Θ(d(v))= Θ(|V|+|E|) v∈V u 5 Carsten Gutwenger DAP2 SS09 23 Carsten Gutwenger DAP2 SS09 24 4 BFS-Baum vs. DFS-Baum BFS-Baum 1 2 BFS & DFS a 3 Höhe eindeutig 1 2 2 a b c c d e e 3 3 f 4 g DFS-Baum 6 7 Carsten Gutwenger 5 DAP2 SS09 BFS-Baum 25 Kap. 6.4 Elementare Graphenalgorithmen 27 C4 T-Kanten des DFS-Waldes Carsten Gutwenger DAP2 SS09 DFS-Baum Carsten Gutwenger DAP2 SS09 26 Carsten Gutwenger DAP2 SS09 28 Idee: • Beginne an einem Knoten s und bestimme alle von s aus erreichbaren Knoten → Komponente 1 (Markierung mit 1) • Beginne nun bei einem noch unmarkierten Knoten v (marked==0) und bestimme alle von v aus erreichbaren Knoten; markiere dabei mit 2 → Komponente 2 • …u.s.w. bis alle Knoten markiert sind C3 C2 b Bestimmen der Zusammenhangskomponenten Komponenten eines Graphen C1 g • G heißt zusammenhängend (connected), wenn |V|≧1 und für jedes Paar u,v von Knoten ein Weg von u nach v in G existiert. • Ein Graph G´=(V´,E´) mit V´⊆ V und E´⊆ E ist ein Untergraph (Teilgraph, subgraph) von G. Wir schreiben G´⊆G. • Eine (Zusammenhangs-) Komponente (component) von G ist ein maximaler zusammenhängender Untergraph U von G, d.h. es gibt keinen anderen zusammenhängenden Untergraphen U´ mit U⊆U´. Zusammenhangskomponenten DAP2 SS09 d Definitionen (Zusammenhang) Kap. 6.4.1 Komponenten eines Graphen Carsten Gutwenger f 29 Carsten Gutwenger DAP2 SS09 30 5 Algorithmus COMPONENTS(G) Bestimmen der Zusammenhangskomponenten Sei G=(V,E) ungerichteter Graph, v,w: Knoten (1) for all v∈V do { marked[v]:=0} (2) numComps:=0 (3) for all v∈V do { (4) if marked[v]=0 then { (5) numComps:=numComps+1 (6) DFS-COMP(v) (7) } } (8) Procedure DFS-COMP(Node v) (9) marked[v]:=numComps (10) for all w∈N(v) do (11) if marked[w]=0 then (12) DFS-COMP(w) Theorem: Der Algorithmus COMPONENTS(G) bestimmt die Zusammenhangskomponenten eines Graphen G=(V,E) in Zeit Θ(|V|+|E|). Carsten Gutwenger Kap. 6.4.2 Kreise in Graphen DAP2 SS09 32 Kreise und DFS • Lemma: Sei G ein ungerichteter Graph und F ein beliebiger DFS-Wald für G. Dann ist G genau dann kreisfrei, wenn G keine Rückwärtskante (B-Kante) bezüglich F enthält. • Aufgabe: Gegeben ist ein ungerichteter Graph G=(V,E). Enthält G einen Kreis? • Idee: mittels DFS Beweis: • 1. Fall: F enthält keine B-Kante: dann besteht F nur aus T-Kanten → F enthält alle Kanten aus G → G kreisfrei • 2. Fall: Sei (u,v) B-Kante bzgl. F → es existiert Weg v,…,u mit T-Kanten in F → Weg mit Kante (u,v) bildet Kreis in G. Carsten Gutwenger DAP2 SS09 33 DAP2 SS09 34 Algorithmus ISACYCLIC(G) Kreise und DFS Sei G=(V,E) ungerichteter Graph • Methode: Erweitere DFS um Speicherung der B-Kanten: sobald wir von v aus auf einen markierten Knoten u treffen, haben wir eine BKante gefunden, falls u nicht der direkte Vorgänger (Elter) von v ist. (1) function ISACYCLIC(Graph G=(V,E)) : bool { (2) B := ∅ (3) for all v∈V do { marked[v]:=false; π(v):=nil } (4) for all v∈V do { (5) if not marked[v] then (6) DFS-ACYCLIC(v) (7) } (8) if B ∅ then return false else return true (9) } Algorithmus ISACYCLIC(G) speichert dabei alle B-Kanten. Wenn man nur einen Kreis finden möchte, dann kann man abbrechen, sobald man eine B-Kante gefunden hat. Carsten Gutwenger Carsten Gutwenger DAP2 SS09 35 Carsten Gutwenger DAP2 SS09 36 6 Algorithmus ISACYCLIC(G) ff Welche Kreise werden gefunden? (1) procedure DFS-ACYCLIC(Node v) { (2) marked[v] := true (3) for all w ∈ N(v) do (4) if not marked[w] then (5) π[w] := v (6) DFS-ACYCLIC(w) (7) else if π [v] w then (8) B := B (v,w) (9) } (10) } Carsten Gutwenger Pfad von T-Kanten + eine B-Kante c e DAP2 SS09 37 Test auf Kreisfreihet DAP2 SS09 39 5. gerichteter Graph Kante (x,y) Aufgabe x muss abgeschlossen werden, bevor mit y angefangen werden kann DAP2 SS09 DAP2 SS09 38 Carsten Gutwenger DAP2 SS09 40 Definition: Ein DAG (directed acyclic graph) ist ein gerichteter Graph, der keinen (gerichteten) Kreis enthält. Dach eindecken Carsten Gutwenger Carsten Gutwenger Graph ist azyklisch! (also keine zyklischen Abhängigkeiten) Baugrube Fenster b Grundvoraussetzung: Dachstuhl 1. 4. g DAG 3. Mauern d Achtung: in diesem Abschnitt gerichtete Graphen! Modellierung von Abhängigkeiten 2. f Kap. 6.4.3 Topologisches Sortieren Theorem: Die Funktion ISACYCLIC(G) testet einen ungerichteten Graphen G=(V,E) auf Kreisfreiheit in Zeit Θ(|V|+|E|). Carsten Gutwenger a 41 Carsten Gutwenger DAP2 SS09 42 7 Topologisches Sortieren Warum ist dies nicht mit BFS lösbar? Dachstuhl Mauern Gegeben: DAG G = (V,A) Gesucht: 3. 2. Topologisches Sortieren 1. eine Sortierung v1,…,vn der Knoten von G mit i<j für alle (vi,vj) A Baugrube 5. 4. Fenster v1 v2 v3 v4 v5 v6 v8 v7 Carsten Gutwenger v9 graphentheoretische Distanz von Baugrube zu Fenster = 1 (BFS), aber Fenster darf erst nach Mauer ausgeführt werden v10 DAP2 SS09 43 Quellen & Senken • Eine Quelle ist ein Knoten ohne eingehende Kanten • Eine Senke ist ein Knoten ohne ausgehende Kanten Quelle Senke Carsten Gutwenger DAP2 SS09 Carsten Gutwenger DAP2 SS09 44 Beobachtung: Jeder (nicht-leere) DAG G =(V,A) hat mindestens eine Quelle und eine Senke. Beweis: Annahme: G hat keine Senke • Verfolge von u1 an immer ausgehende Kanten pi := u1,u2,…,ui solange bis i > |V| oder keine ausgehende Kante mehr existiert • Falls i > |V| ein Knoten zweimal auf pi • Kreis! Widerspruch! • Analog für Quelle 45 Algorithmus Carsten Gutwenger DAP2 SS09 46 Verbesserungen Wie finden wir effizient eine Quelle? • Wird v gelöscht, dann können nur Zielknoten w von Kanten (v,w) neu zu Quellen werden. • Genügt ausgehende Nachbarmenge A -(v) zu betrachten. Idee: Wähle immer Quelle und entferne sie dann while G ist nicht leer do Wähle eine Quelle s in G und gib sie aus G := G - s end while Carsten Gutwenger Dach eindecken DAP2 SS09 Müssen wir Knoten wirklich löschen? • Nein! Verwalte Eingangsgrad in Knotenfeld indeg. 47 Carsten Gutwenger DAP2 SS09 48 8 Algorithmus TopSort (1) (2) var Queue Q var int indeg[V] (3) (4) (5) (6) (7) // Initialisierung for all v ∈ V do { indeg[v] := d +(v) if indeg[v] = 0 then Q.PUT(v) } Carsten Gutwenger Algorithmus TopSort (2) (8) // Hauptschleife (9) while not Q.ISEMPTY() do { (10) v := Q.GET() (11) Gib v aus (12) for all (v,u) ∈ A-(v) do { (13) indeg[u] := indeg[u] - 1 (14) if indeg[u] = 0 then Q.PUT(u) (15) } (16) } DAP2 SS09 49 Beispiel: TopSort a b c d Q a e j b f c DAP2 SS09 50 Analyse der Laufzeit Ausgabe: a j f j b f c g i e d h g h e d g h i i Carsten Gutwenger Carsten Gutwenger DAP2 SS09 • Initialisierung: (|V|) (da d +(v) in konstanter Zeit abrufbar) • Jeder Knoten kommt genau einmal in Q while-Schleife wird |V|-mal durchlaufen • Die for all-Schleife (Zeile 12) wird insgesamt für jede Kante einmal durchlaufen: (|A|) • Gesamtaufwand: (|V |+|A|) 51 Carsten Gutwenger DAP2 SS09 52 Analyse TopSort Theorem: Der Algorithmus TopSort berechnet eine topologische Sortierung der Knoten eines DAGs G=(V,A) in Zeit (|V|+|A|). Carsten Gutwenger DAP2 SS09 53 9