Aufgabe 31 Aufgabe 32

Werbung
Datenstrukturen und Algorithmen
Musterlösung zu Heimübungsblatt 9
Sebastian Kniesburges
Aufgabe 31
(a)
Eine topologische Sortierung ist 5, 2, 1, 6, 8, 7, 4, 3 oder auch 5, 6, 8, 7, 2, 1, 4, 3
(b)
Die topologische Sortierung wird nur für DAGs definiert, da für allgemeine gerichtete
oder ungerichtete Graphen kein vernünftiger Begriff existiert. Die Knoten eines Graphen
können bei Kreisen oder ungerichteten Kanten in keine konsistente Ordnung gebracht
werden. Die topologische Sortierung ist als lineare Ordnung der Knoten definiert, sodass
u vor v in der Sortierung steht, falls die Kante (u, v) existiert. Bei ungerichteten Graphen
müsste also u vor v und v vor u stehen. Gleiches gilt für Kreise in gerichteten Graphen.
(c)
entspricht Lemma 36.
⇒ Es existiert eine Rückwärtskante (u, v). Dann ist v ein Ahne von u, das heißt es
existiert ein Weg von v nach u und die Kante (u, v) schließt den Kreis.
⇐ Der Graph G enthält einen Kreis c. Sei v der erste von DF S entdeckte Knoten in
c und (u, v) die vorherige Kanten im Kreis c. Da u bisher nicht entdeckt wurde, wird
er zu einem Nachfolger von v, damit ist (u, v) eine Rückwärtskante. Also ist ein Graph
genau dann zyklisch, wenn DF S eine Rückwärtskante liefert. Entsprechend ist er genau
dann azyklisch, wenn DF S keine Rückwärtskante liefert.
(d)
Nach b) kann der Algorithmus nur auf DAGs angewendet werden. Nach c) liefert DF S
für DAGs keine Rückwärtskanten. Also liefert DF S nur Baum-, Kreuzungs- und Vorwärtskanten. Für all die Kanten gilt: Für eine Kante (u, v) gilt f [u] > f [v].
Für eine Baumkante (u, v) gilt: v ist ein Nachfahre von u und somit f [u] > f [v].
Für Kreuzungs- und Vorwärtskanten gilt: v ist schwarz und u ist grau bei der Entdeckung von (u, v). Also f [u] > f [v], da v bereit abgeschlossen wurde.
Da für alle Kanten (u, v) gilt f [u] > f [v], liefert der Algorithmus ein korrektes Ergebnis.
Aufgabe 32
Gegenbeispiel:
Datenstrukturen und Algorithmen
Musterlösung zu Heimübungsblatt 9
Sebastian Kniesburges
Der Dijkstra Algorithmus liefert:
Hierbei entpricht der erste Eintrag eines Knotens der Entfernung und der zweite dem
Vorgänger.
Der kürzeste Weg von a nach c über b mit Kosten 1 wird also nicht gefunden.
Aufgabe 33
Zunächst wird ein Array mit W |V | Einträgen angelegt. Hierbei ist {0, . . . , W |V |} der
Wertebereich der Pfadlängen. Die maximale Entfernung eines Knoten zum Statknoten
kann nicht größer sein als W |V |. Jedes Array-Element ist ein Zeiger auf eine doppelt
verkettete Liste. Ein Knoten wird entsprechend seinem d-Wert, also seiner Distanz zum
Startknoten, in die Liste mit dem Index d[v] eingefügt. Der Array wird mit leeren Listen
initialisiert. Bis auf die erste Liste, in diese wird der Startknoten eingefügt. Bei der Suche
nach dem Minimum wird ausgehend von dem letzten Minimum das Array durchsucht,
d.h. das Array wird von Index des letzten Minimums an nach rechts (aufsteigende Indizes) durchsucht. Dies funktioniert deshalb, da durch Relaxation nie ein d-Wert gebildet
werden kann der kleiner als der zuletzt selektierte d-Wert ist. Denn alle Kantengewichte
sind positiv, sonst wäre der Dijkstra-Algorithmus nicht anwendbar. Die Kosten für die
Extraktion der Knoten aus dem Array betragen somit O(W |V |). Denn das Array wird
genau einmal durchlaufen. Die Decrease-Key-Operation kann in O(1) durchgeführt werden. Dazu ist ein Pointer-Array nötig der auf Zeiger auf die Knoten enthält. Wird nun
der Knoten v relaxiert, so verweist der ZEiger an der Stelle v auf den entsprechenden
Knoten. Der Knoten wird aus der Liste mit Index dalt [v] entfernt, indem die Zeiger beim
Vorgänger und Nachfolger umgehängt werden und in die Liste dneu [v] eingefügt. Der
Datenstrukturen und Algorithmen
Musterlösung zu Heimübungsblatt 9
Sebastian Kniesburges
Zugriff auf die Liste dneu [v], ist in O(1) möglich, da nur auf das entsprechende Feld des
Array zugegriffen werden muss. Auch das Umhängen der Zeiger ist in O(1) möglich. Der
Gesamtaufwand beträgt somit O(W |V | + E).
Aufgabe 34
Definition Eulerkreis: Sei G = (V, E) ein gerichteter Graph. Ein Kreis C in G heißt
Eulerkreis, wenn C jede Kante aus E genau einmal enthält. Einzelne Knoten dürfen in
C mehrfach vorkommen.
Satz (Euler, Hierholzer) Ein endlicher gerichteter und schwach zusammenhängender
Graph G = (V, E) besitzt genau dann einen Eulerkreis, wenn für alle v ∈ V gilt: Indegree(v) = Outdegree(v).
Definition Ein endlicher gerichteter Graph ist schwach zusammenhängend, wenn der
entsprechende ungerichtete Graph zusammenhängend ist.
Satz: Sei C ein Kreis in G, der die Kanten E(C) und die Knoten V (C) enthält. Der
0
Restgraph G = (V, EE(C)) enthält genau dann noch Kanten, wenn es einen Knoten
0
u ∈ V (C) gibt, von dem noch Kanten in G ausgehen.
Idee:
Zunächst wird mit Hilfe der Eigenschaft aus dem Satz von Euler bzw. Hierholzer (Indegree(v) = Outdegree(v) für alle v ∈ V ) überprüft, ob der Graph einen Eulerkreis enthält.
Dies in Zeit O(|V | + |E|) möglich bei gegebener Adjazenzlistendarstellung des Graphen.
Wir bestimmen ausgehend von einem Knoten v0 einen Kreis C = (v0 → v1 . . . → vk ).
Anschließend durchlaufen wir den Kreis C erneut und prüfen, ob es einen Knoten in
V (C) gibt, von dem noch Kanten aus E E(C) starten. Sei vi der erste solche Knoten in
V (C). Wir konstruieren nun ausgehend von vi solange kantendisjunkte Kreise, bis in vi
keine unbenutzte Kanten mehr starten. Alle diese Kreise fügen wir in den Kreis C nach
dem Knoten vi ein. Danach setzen wir unseren Durchlauf des aktualisierten Kreises C
an der Stelle vi fort und suchen den nächsten Knoten von dem noch Kanten aus E E(C)
starten.
ERFORSCHE(G, v, current) konstruiert ausgehend von v einen Kreis K aus noch unbenutzten Kanten. current sei dabei ein Array von Zeigern auf die aktuellen Listeneinträge
in den Adjazenzlisten.
ERFORSCHE(G, v, current)
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
u←current[v]
current[v]←next[current[v]]
K←(v,u)
while u 6= v do
w←current[u]
current[u]←next[current[u]]
K←K∪(u→w)
u←w
end while
return K
EULER(G) konstruiert in Linearzeit einen Eulerkreis.
EULER(G)
1: for all v ∈ V do
Datenstrukturen und Algorithmen
Musterlösung zu Heimübungsblatt 9
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
Sebastian Kniesburges
current[v]←head[ADJ[v]]
end for
C←(v0 )
v←v0
repeat
while current[v] 6= Nil do
K←ERFORSCHE(G, v, current)
Füge K in C an der Stelle v ein
end while
v← v0 mit v0 folgt v in C
until v = v0
return C
Laufzeit
Jede Kante des Graphen wird genau einmal durch einen Aufruf von ERFORSCHE in
einen Kreis aufgenommen und danach aus dem Graphen gelöscht“, d.h. mit Hilfe des
”
current-Zeiger als benutzt markiert. Somit ist der gesamte Aufwand für alle Aufrufe von
ERFORSCHE und damit auch für alle Durchläufe der While-Schleife in der Größenordnung O(|E|). Da der letztlich konstruierte Eulerkreis genau |E| + 1 Knoten enthält,
finden insgesamt auch nur O(|E|) Durchläufe der Repeat-Until-Schleife statt. Die Initialisierung ist in O(|V |) durchführbar. Insgesamt ergibt sich daher eine Laufzeit von
O(|V | + |E|).
Herunterladen