110 likes | 209 Views
Tarjans Algorithmus zur Bestimmung der starken Zusammenhangs- komponenten. Katja Losemann Chris Schwiegelshohn. Idee. G = <V,E> gerichteter Graph Gesucht sind alle starken Zusammenhangskomponenten (SZK) Einmalige Tiefensuche durch den Graph reicht aus
E N D
Tarjans Algorithmus zur Bestimmung der starken Zusammenhangs- komponenten Katja Losemann Chris Schwiegelshohn
Idee • G = <V,E> gerichteter Graph • Gesucht sind alle starken Zusammenhangskomponenten (SZK) • Einmalige Tiefensuche durch den Graph reicht aus • SZK werden durch Wurzeln der DFS-Teilbäume eindeutig identifiziert
Idee (Forsetzung) • dfs_index(v): Reihenfolge der DFS-Aufrufe • Stack S wird in der Reihenfolge der besuchten Knoten befüllt • Bei Rückkehr Überprüfung ob aktueller Knoten v die Wurzel einer SZK • Wenn eine Wurzel gefunden wurde, bilden alle Knoten des Stacks bis zu dieser Wurzel eine SZK
Lowlink • zusätzlicher Wert lowlink(v) für alle v mit • lowlink(v) =min ( {num[v]} {num[x] | v→*−x ) • v Wurzel, wenn lowlink(v) = dfs(v)
Algorithmus Eingabe Graph G ( V, E ) current_dfs := 0 V‘ := V S = ∅ // S ist der Stack while ( V‘ not emtpy) tarjan ( v ) // v ∊ V‘
Algorithmus (Forsetzung) Tarjan ( v ) : dfs_index( v ) := current_dfs lowlink( v ) := current_dfs S.push ( v ) current_dfs ++ V‘ = V \ { v } For ( v1 | ( v, v1 ) ∊ E ) if ( v1 ∊ V‘ ) tarjan ( v1 ) lowlink( v ) := min ( lowlink( v ), lowlink( v1 ) )
Algorithmus (Forsetzung) else if (v1 ∊ S ) lowlink( v ) := min ( lowlink( v ), dfs_index( v1 ) ) If ( lowlink( v ) = dfs_index( v ) ) repeat k = S.pop( ) //Ausgabe until ( k = v )
Beispiel dfs(v) lowlink(v)) lowlink(1) = 1 lowlink(5) = 2 11 0 10 12 lowlink(4) = 2 lowlink(9) = 6 lowlink(8) = 6 1 5 lowlink(7) = 6 8 9 lowlink(6) = 6 4 lowlink(3) = 0 lowlink(2) = 0 2 3 7 lowlink(10) = 3 6 lowlink(0) = 0 9 SZK 1 SZK 0,2,3,4,5 lowlink(12) = 11 8 7 SZK 6,7,8,9 SZK 11,12 lowlink(11) = 11 6 10 5 4 3 12 2 1 0 11 Stack:
Beweis – Korrektheit lowlink • Fall 1: (v‘‘,v‘) Vorwärtskante • Dann dfs(v‘) > dfs(v‘‘) trägt nicht zum Min bei • Fall 2: (v‘‘,v‘) Rückwärtskante • Dann v‘ noch auf dem Stack und in gleicher SZK • Fall 3: (v‘‘,v‘) Querkante • Entweder nicht im Stack und in nächster SZK, • oder nicht im Stack und in gleicher SZK, dann aber normale Baumkante
Beweis - Korrektheit • lowlink garantiert, dass es immer einen Weg zu einem Knoten höher im DFS-Baum als der aktuelle Knoten existiert • lowlink(v) = dfs(v) ⇒ Kein Knoten oberhalb von v kommt für SZK in Frage • Mit der letzten Kante kommt man nicht in eine SZK, die nicht aktuell und auf dem Stack liegt. • Wäre ein Weg nur in einer Richtung vorhanden, wäre lowlink(v) = dfs(v)
Aufwand • Aber ist das effizient berechenbar? • Tarjan muss für jeden Knoten einmal aufgerufen werden • Die Berechnung von dfs und lowlink erfolgt rekursiv über alle angrenzenden Kanten • Insgesamt wird jede Kante maximal 2x betrachtet, damit: • O( |V| + |E| )