Datenstrukturen und Algorithmen
Musterl¨osung zu Heim¨ubungsblatt 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¨ur DAGs definiert, da f¨ur allgemeine gerichtete oder ungerichtete Graphen kein vern¨unftiger Begriff existiert. Die Knoten eines Graphen k¨onnen bei Kreisen oder ungerichteten Kanten in keine konsistente Ordnung gebracht werden. Die topologische Sortierung ist als lineare Ordnung der Knoten definiert, sodass uvorvin der Sortierung steht, falls die Kante (u, v) existiert. Bei ungerichteten Graphen m¨usste alsouvorv undv vorustehen. Gleiches gilt f¨ur Kreise in gerichteten Graphen.
(c)
entspricht Lemma 36.
⇒ Es existiert eine R¨uckw¨artskante (u, v). Dann ist v ein Ahne von u, das heißt es existiert ein Weg von v nachu und die Kante (u, v) schließt den Kreis.
⇐ Der Graph G enth¨alt 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¨uckw¨artskante. Also ist ein Graph genau dann zyklisch, wennDF Seine R¨uckw¨artskante liefert. Entsprechend ist er genau dann azyklisch, wennDF S keine R¨uckw¨artskante liefert.
(d)
Nach b) kann der Algorithmus nur aufDAGs angewendet werden. Nach c) liefertDF S f¨ur DAGs keine R¨uckw¨artskanten. Also liefert DF S nur Baum-, Kreuzungs- und Vor- w¨artskanten. F¨ur all die Kanten gilt: F¨ur eine Kante (u, v) giltf[u]> f[v].
F¨ur eine Baumkante (u, v) gilt:v ist ein Nachfahre von u und somitf[u]> f[v].
F¨ur Kreuzungs- und Vorw¨artskanten gilt: v ist schwarz und u ist grau bei der Entde- ckung von (u, v). Alsof[u]> f[v], dav bereit abgeschlossen wurde.
Da f¨ur alle Kanten (u, v) giltf[u]> f[v], liefert der Algorithmus ein korrektes Ergebnis.
Aufgabe 32
Gegenbeispiel:
Datenstrukturen und Algorithmen
Musterl¨osung zu Heim¨ubungsblatt 9 Sebastian Kniesburges
Der Dijkstra Algorithmus liefert:
Hierbei entpricht der erste Eintrag eines Knotens der Entfernung und der zweite dem Vorg¨anger.
Der k¨urzeste Weg von anach cuber¨ bmit Kosten 1 wird also nicht gefunden.
Aufgabe 33
Zun¨achst wird ein Array mit W |V|Eintr¨agen angelegt. Hierbei ist {0, . . . , W|V|} der Wertebereich der Pfadl¨angen. Die maximale Entfernung eines Knoten zum Statknoten kann nicht gr¨oß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 Indexd[v] eingef¨ugt. Der Array wird mit leeren Listen initialisiert. Bis auf die erste Liste, in diese wird der Startknoten eingef¨ugt. 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 Indi- zes) 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¨are der Dijkstra-Algorithmus nicht anwendbar. Die Kosten f¨ur die Extraktion der Knoten aus dem Array betragen somitO(W |V|). Denn das Array wird genau einmal durchlaufen. Die Decrease-Key-Operation kann inO(1) durchgef¨uhrt wer- den. Dazu ist ein Pointer-Array n¨otig der auf Zeiger auf die Knoten enth¨alt. 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 Indexdalt[v] entfernt, indem die Zeiger beim Vorg¨anger und Nachfolger umgeh¨angt werden und in die Liste dneu[v] eingef¨ugt. Der
Datenstrukturen und Algorithmen
Musterl¨osung zu Heim¨ubungsblatt 9 Sebastian Kniesburges Zugriff auf die Listedneu[v], ist inO(1) m¨oglich, da nur auf das entsprechende Feld des Array zugegriffen werden muss. Auch das Umh¨angen der Zeiger ist inO(1) m¨oglich. Der Gesamtaufwand betr¨agt somit O(W |V|+E).
Aufgabe 34
Definition Eulerkreis:Sei G= (V, E) ein gerichteter Graph. Ein KreisC inG heißt Eulerkreis, wennC jede Kante ausE genau einmal enth¨alt. Einzelne Knoten d¨urfen in C mehrfach vorkommen.
Satz (Euler, Hierholzer)Ein endlicher gerichteter und schwach zusammenh¨angender GraphG= (V, E) besitzt genau dann einen Eulerkreis, wenn f¨ur allev ∈V gilt: Inde- gree(v) = Outdegree(v).
Definition Ein endlicher gerichteter Graph ist schwach zusammenh¨angend, wenn der entsprechende ungerichtete Graph zusammenh¨angend ist.
Satz: Sei C ein Kreis in G, der die Kanten E(C) und die Knoten V(C) enth¨alt. Der Restgraph G0 = (V, EE(C)) enth¨alt genau dann noch Kanten, wenn es einen Knoten u∈V(C) gibt, von dem noch Kanten inG0 ausgehen.
Idee:
Zun¨achst wird mit Hilfe der Eigenschaft aus dem Satz von Euler bzw. Hierholzer (Inde- gree(v) = Outdegree(v) f¨ur allev∈V) ¨uberpr¨uft, ob der Graph einen Eulerkreis enth¨alt.
Dies in ZeitO(|V|+|E|) m¨oglich 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¨ufen, ob es einen Knoten in V(C) gibt, von dem noch Kanten aus E E(C) starten. Seivi der erste solche Knoten in V(C). Wir konstruieren nun ausgehend vonvi solange kantendisjunkte Kreise, bis invi
keine unbenutzte Kanten mehr starten. Alle diese Kreise f¨ugen wir in den Kreis C nach dem Knoten vi ein. Danach setzen wir unseren Durchlauf des aktualisierten Kreises C an der Stellevifort und suchen den n¨achsten Knoten von dem noch Kanten aus E E(C) starten.
ERFORSCHE(G, v, current) konstruiert ausgehend vonveinen Kreis K aus noch unbe- nutzten Kanten. current sei dabei ein Array von Zeigern auf die aktuellen Listeneintr¨age in den Adjazenzlisten.
ERFORSCHE(G, v, current)
1: u←current[v]
2: current[v]←next[current[v]]
3: K←(v,u)
4: whileu6=v do
5: w←current[u]
6: current[u]←next[current[u]]
7: K←K∪(u→w)
8: u←w
9: end while
10: return K
EULER(G) konstruiert in Linearzeit einen Eulerkreis.
EULER(G)
1: for allv∈V do
Datenstrukturen und Algorithmen
Musterl¨osung zu Heim¨ubungsblatt 9 Sebastian Kniesburges
2: current[v]←head[ADJ[v]]
3: end for
4: C←(v0)
5: v←v0
6: repeat
7: while current[v]6= Nildo
8: K←ERFORSCHE(G, v, current)
9: F¨uge K in C an der Stelle v ein
10: end while
11: v←v0 mitv0 folgt v in C
12: untilv = v0
13: 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¨oscht“, d.h. mit Hilfe des current-Zeiger als benutzt markiert. Somit ist der gesamte Aufwand f¨ur alle Aufrufe von ERFORSCHE und damit auch f¨ur alle Durchl¨aufe der While-Schleife in der Gr¨oßen- ordnungO(|E|). Da der letztlich konstruierte Eulerkreis genau|E|+ 1 Knoten enth¨alt, finden insgesamt auch nur O(|E|) Durchl¨aufe der Repeat-Until-Schleife statt. Die In- itialisierung ist in O(|V|) durchf¨uhrbar. Insgesamt ergibt sich daher eine Laufzeit von O(|V|+|E|).