6. Graphen
6.2 Zusammenhang, Kreise finden, Tiefensuche, Breitensuche
Der erste algorithmische Problem, das wir untersuchen werden, ist Graphenzusammenhang.
Algorithmisches Problem 6.2.2
(
Wir haben dies als ein Entscheidungsproblem formuliert, also als Ja/Nein-Frage. In der Komplexitätstheorie untersuchen wir vorwiegend solche Entscheidungsprobleme. In der Praxis wollen wir natürlich nicht nur eine Ja/Nein-Antwort, sondern in diesem konkreten Fall auch den Pfad, sollte er denn existieren.
Wir lösen
def depthFirstSearch(u):
if marked[u]: return
else:
marked[u] = true
for v in neighbors(u):
depthFirstSearch(v)
marked
als [false, ..., false]
initialisieren und depthFirstSearch(u)
aufrufen,
dann terminiert der Aufruf; nach Terminierung ist
marked[v] = true
genau dann, wenn es einen Pfad von
u
nach v
gibt.
In Graph.java finden Sie eine einfache Graphen-Klasse. Meine Implementierung von Tiefensuche finden Sie in UndirectedConnectivity.java.
input-01.txt
/ output-01.txt
und vergleichen Sie meinen
Output mit dem von Ihnen per Hand geschriebenen "korrekten" Output.
(Beachten Sie, dass die Meldungen please enter n:
etc. von
meinem Programm auf System.err
gedruckt werden; wenn Sie
java UndirectedConnectivity < input-xx.txt > output-dominik-xx.txt
machen,
dann wird output-dominik-xx.txt
nur den "echten" Output
enthalten, nicht aber die Meldungen).
Im folgenden werde ich Sie bitten, aufbauend auf meinem Code (oder
auch from scratch, wenn Sie wollen), Algorithmen für mehrere Probleme
zu implementieren.
Schreiben Sie zu jedem Problem auch ein paar Test-Cases.
Alle Algorithmen sollten Laufzeit
diff
mit meiner oder anderen vergleichen kann.
Übungsaufgabe 6.2.3
Erweitern Sie meine Datei UndirectedConnectivity,
so dass es nicht eine True/False-Tabelle ausgibt, sondern neben dem Startknoten
java UndirectedConnectivity
5 6 4 0 0 1 0 2 1 2 1 3 2 3 4 3yes
4
0
1
3
Cyclicity
, das testet, ob der gegebene Graph
einen Kreis enthält.
Input. Ein Graph in dem oben definierten Format.
Output. Eine einzelne Zeile, die entweder
das Wort cyclic
oder acyclic
enthält.
Die Zusammenhangskomponente von
Input. Ein Graph im obigen Format.
Output.
Beispiel-Input (für Graph
):
6 4 4 0 1 3 1 2 2 3
Beispiel-Output:
0 0 1 1 2 1 3 1 4 0 5 5
Input. Ein Graph s t
, die zwei
int
enthält.
Output.
Falls es keinen Pfad in false
in einer
einzelnen Zeile. Falls es einen Pfad gibt:
ein solcher Pfad, beginnend mit
Breitensuche: kürzeste Wege finden
Tiefensuche erlaubt uns, zu erkennen, ob es einen Pfad
von queue
und ein Array visited
, das uns anzeigt, ob
ein Knoten bereits einmal in der Warteschlange war.
def breadthFirstSearch(s):
queue = new Queue();
visited = [false, ..., false]
queue.push(s)
visited[s] = true
while (active.size() > 0):
u = queue.pop()
for v in neighbors(u):
if (!visited[v]):
visited[v] = true
queue.push(v)
return visited
breadthFirstSearch
terminiert hat,
ist visited[u] = true
genau dann, wenn es einen Pfad
von s
nach u
gibt.
Darüberhinaus gilt: wenn Zeilen 10 und 11 durchlaufen werden,
dann gilt Meine Java-Implementierung finden Sie in BreadthFirstSearch.java.
Input. Ein Graph im obigen Format, gefolgt von
einer Zeile, die ein einzelnes int
enthält: den Knoten
5 6 0 1 0 2 0 4 1 2 1 3 2 3 4
Output. int
enthalten. Die
0 1 1 2 2 2 3 3 4 0Solle es keinen Pfad von