Stellen Sie sich vor, Sie steuern einen Roboter, der sich an einem bestimmten Ort in einem Graphen mit n Knoten und e Kanten befindet. Sie möchten von einem Startknoten aus nach und nach den gesamten Graphen erkunden und alle erreichbaren Knoten besuchen. Der DFS-Algorithmus macht genau das, indem er von einem Startknoten aus einen Pfad so weit wie möglich verfolgt. Sobald es dort keine neuen Knoten mehr gibt, geht er auf die vorherigen Knoten zurĂŒck und sucht von dort neue, noch nicht besuchte Wege.
Video von Reducible â Depth First Search (DFS) erklĂ€rt: Algorithmus, Beispiele und Code
Eine hilfreiche Vorstellung fĂŒr den DFS-Algorithmus ist die Idee eines Roboters, der von Knoten zu Knoten geht. Er kann nur die Nachbarn des aktuellen Knotens und jene Knoten sehen, die er schon besucht hat (er behĂ€lt also den gesamten Weg im Blick). Dieses Vorgehen ist ein rekursiver Prozess: In jedem Schritt bewegt sich der Roboter zu einem bisher unbesuchten Knoten und wiederholt das Vorgehen, bis kein weiterer unentdeckter Knoten mehr auf diesem Pfad liegt. Wenn man sich das als kleinen Roboter vorstellt, ist die Umsetzung oft einfacher.
Die Implementierung des DFS-Algorithmus kann mithilfe einer rekursiven Funktion umgesetzt werden. Dabei behalten wir den aktuellen Knoten (den wir mit v bezeichnen) und alle bereits besuchten Knoten (in used) im Blick:
import sys
sys.setrecursionlimit(10 ** 6) # Erhöht das Rekursionslimit, damit DFS korrekt ausgefĂŒhrt werden kann
n, e = map(int, input().split()) # n: Knoten, e: Kanten
g = [[] for _ in range(n)] # Graph - Adjazenzliste
used = [False] * n # bereits besuchte Knoten
for _ in range(e): # Kanten einlesen
a, b = map(int, input().split()) # a -> b und b -> a
g[a].append(b)
g[b].append(a)
def dfs(v): # Tiefensuche
used[v] = True # Knoten als besucht markieren
print(v, end=' ') # Knoten ausgeben
for to in g[v]: # fĂŒr jeden mit v verbundenen Knoten
if not used[to]: # falls Knoten noch nicht besucht
dfs(to) # DFS fĂŒr diesen Knoten aufrufen
start = int(input()) # Startknoten einlesen
dfs(start) # DFS vom Startknoten aus aufrufen
ZunÀchst initialisieren wir also den Graphen und beginnen die Traversierung beim Knoten start. Alle Werte in used sind anfangs False. Sobald wir einen Knoten besuchen, setzen wir ihn mit used[v] = True auf besucht und gehen dann alle Nachbarn des aktuellen Knotens v durch.
Die Rekursion ĂŒbernimmt dabei die Rolle, den Weg zu erkunden. Sobald ein Pfad erschöpft ist, âkehrtâ die Funktion zur vorherigen Position zurĂŒck, um von dort aus die ĂŒbrigen Nachbarn zu durchsuchen. Wenn wir uns mit der RĂŒckkehr aus der Rekursion gedanklich wieder zum Knoten davor âbewegenâ, verstehen wir leicht, wie der Algorithmus arbeitet.
Werfen wir einen Blick auf einige Eingaben und deren AblÀufe:
n = 4, e = 4
Die eingegebenen Paare a, b lauten: [(0, 1), (0, 2), (1, 2), (3, 2)]
Der Startknoten ist 3
v = 3 â used = [False, False, False, True]
Durchsuche alle Nachbarn von 3 â [2]
v = 2 â used = [False, False, True, True]
Durchsuche alle Nachbarn von 2 â [0, 1]
v = 0 â used = [True, False, True, True]
Durchsuche alle Nachbarn von 0 â [1, 2]
v = 1 â used = [True, True, True, True]
Durchsuche alle Nachbarn von 1 â [0, 2] â alle besucht
ZurĂŒckkehren von 1
ZurĂŒckkehren von 0
ZurĂŒckkehren von 2
ZurĂŒckkehren von 3 â DFS beendet
Fertig
n = 5, e = 4
Die eingegebenen Paare a, b lauten: [(0, 1), (0, 2), (1, 2), (3, 4)]
Der Startknoten ist 0
v = 0 â used = [True, False, False, False, False]
Durchsuche alle Nachbarn von 0 â [1, 2]
v = 1 â used = [True, True, False, False, False]
Durchsuche alle Nachbarn von 1 â [0, 2]
v = 2 â used = [True, True, True, False, False]
Durchsuche alle Nachbarn von 2 â [0, 1] â alle besucht
ZurĂŒckkehren von 2
ZurĂŒckkehren von 1
ZurĂŒckkehren von 0 â DFS beendet
Fertig
Notice how nodes 3 and 4 were never visited.
They were not connected to the initial node 0.
n = 10, e = 11 (Beispiel aus dem Video)
Die eingegebenen Paare a, b lauten: [(0, 1), (0, 2), (1, 2), (1, 4), (1, 3), (3, 5), (6, 5), (5, 8), (5, 7), (7, 8), (8, 9)]
Der Startknoten ist 0
v = 0 â used = [T, F, F, F, F, F, F, F, F, F] â erkunde [1, 2]
v = 4 â used = [T, T, T, T, T, T, T, T, T, T] â erkunde [1]
ZurĂŒckkehren von 4
ZurĂŒckkehren von 1
ZurĂŒckkehren von 0
Fertig
Â
Herausforderung: Anzahl der zusammenhÀngenden Komponenten zÀhlen
Gegeben ist ein ungerichteter Graph mit v Knoten und e Kanten. Ihre Aufgabe ist es, die Anzahl der zusammenhÀngenden Komponenten dieses Graphen zu bestimmen. Eine Menge von Knoten gilt als eine zusammenhÀngende Komponente, wenn man innerhalb dieser Menge von jedem Knoten jeden anderen Knoten erreichen kann.
Eingabe
Die erste Zeile der Eingabe enthÀlt zwei ganze Zahlen v (1 †v †100 000) und e (1 †e †100 000).
Die folgenden e Zeilen enthalten jeweils ein Paar Ganzzahlen v1, v2 (1 †v1, v2 †v). Dies bedeutet, dass der Knoten v1 mit dem Knoten v2 verbunden ist und umgekehrt.
Ausgabe
Das Programm soll die Anzahl der zusammenhÀngenden Komponenten des Graphen ausgeben.