Musterlösung

Werbung
Prof. Dr. Dennis Hofheinz
Lukas Barth, Lisa Kohl
K a r l s ru h e r I n s t i t u t f ü r T e c h n o l o g i e
Institut für Theoretische Informatik
8. Übungsblatt zu Algorithmen I im SoSe 2016
https://crypto.iti.kit.edu/index.php?id=algo-sose16
{lisa.kohl,lukas.barth}@kit.edu
Musterlösungen
Aufgabe 1
(Breitensuche, 4 Punkte)
Gegeben sei folgender gerichteter Graph mit der Knotenmenge {A, B, C, D, E, F, G}:
A
B
D
C
E
F
G
In diesem Graph werde nun eine Breitensuche durchgeführt, und zwar ausgehend vom Knoten A.
Wählen Sie die Knoten bei mehreren Möglichkeiten jeweils in alphabetischer Reihenfolge aus. (Am
Ende des Übungsblattes finden Sie weitere Kopien dieses Graphs zum anmalen. Wenn Sie diese nutzen,
kennzeichnen Sie bitte eindeutig, welche Kopie die Lösung zu welcher Teilaufgabe enthält.)
a) Zählen Sie die Knoten des Graphen in einer Reihenfolge auf, in der diese von einer Breitensuche
jeweils zum ersten Mal berührt werden. Heben Sie im Graph außerdem alle Kanten (z. B. farbig)
hervor, die bezüglich dieser Breitensuche tree-Kanten sind.
b) Sind im Graph bzgl. dieser Breitensuche irgendwelche backward-Kanten vorhanden? Wenn ja,
heben Sie diese hervor.
c) Sind im Graph bzgl. dieser Breitensuche irgendwelche cross-Kanten vorhanden? Wenn ja, heben
Sie diese hervor.
d) Sind im Graph bzgl. dieser Breitensuche irgendwelche forward-Kanten vorhanden? Wenn ja, heben
Sie diese hervor.
Musterlösung:
Die Knoten werden von einer Breitensuche in der Reihenfolge A, B, C, E, D, G, F besucht.
Im folgenden Graphen sind die tree- bzw. Baumkanten als normale Linien, die cross- bzw. Querkanten
als gestrichelte Linien und die einzige backward- bzw. Rückwärtskante als gepunktete Linie eingezeichnet.
Bei einer Breitensuche können keine forward- bzw. Vorwärtskanten auftreten.
1
A
B
D
C
E
F
G
Aufgabe 2
(Graphrepräsentationen, 4 Punkte)
Ein gerichteter Graph G = (V, E) liege je in der Kantenfolgen-, Adjazenzfeld-, Adjazenzlisten- und
Adjazenzmatrixrepräsentation ohne zusätzliche Informationen vor.
Wie lange dauert es ausgehend von den verschiedenen Repräsentationen jeweils den Ausgangs- und
getrennt davon den Eingangsgrad aller Knoten zu bestimmen? Skizzieren Sie, wie die jeweiligen Algorithmen funktionieren.
Musterlösung:
Kantenfolge Sowohl für das Bestimmen des Eingangs-, als auch des Ausgangsgrades muss die Liste
der Kanten jeweils komplett abgelaufen werden. Währenddessen hält man für jeden Knoten je
einen mit 0 initialisierten Zähler bereit, und inkrementiert diesen jeweils, wenn eine eingehende
(bzw. ausgehende) Kante für diesen Knoten gefunden wurde. Die Laufzeit ist somit O(|V | + |E|).
Adjazenzfeld Das Bestimmen des Ausgangsgrades ist hier effizient: Da das Feld V für jeden Knoten
den Index der ersten ausgehenden Kante in E speichert, lässt sich der Ausgangsgrad von v mittels
V [v + 1] − V [v] bestimmen. Um den Ausgangsgrad aller Knoten zu bestimmen ist also ein Aufwand
von O(|V |) nötig. Im Kantenfeld E sind jeweils die Zielknoten gespeichert, Durchlaufen von E
und zählen wie oft die Knoten jeweils vorkommen liefert daher den Eingangsgrad. Da der Zähler
für die Eingangsgrade der Knoten initialisiert werden muss, ergibt sich insgesamt eine Laufzeit
von O(|V | + |E|).
Adjazenzliste Für doppelt zusammenhängende Listen ohne zusätzliche Informationen (wie in der
Aufgabenstellung gefordert) ergibt sich für Eingangs- wie Ausgangsgrad O(|V | + |E|). Für den
Ausgangsgrad muss jeweils die Länge der angehängten Liste bestimmt werden. Da die Länge aller
Listen sich zu |E| addiert (ein Listenelement pro Kante), ergibt sich die besagte Laufzeit. Für
den Eingangsgrad müssen alle Listen durchlaufen werden und gezählt werden wie oft die Knoten
jeweils vorkommen. (Mit in der in der Vorlesung behandelten Erweiterungen geht das effizienter:
Im Kapitel über Listen wurde vorgestellt, dass man sich manchmal die Länge der verketteten
Liste im Listenkopf speichert, um effizienten Zugriff auf die Listenlänge zu haben. In diesem Fall
wäre dann die Bestimmung des Ausgangsgrades eines Knotens in O(1), für alle Knoten damit in
2
O(|V |). Wendet man nun außerdem die Modifikation der Adjazenzliste von Vorlesungsfolie 22 an,
so hat jeder Knoten nicht nur eine Liste der ausgehenden, sondern auch eine Liste der eingehenden
Kanten. Wenn wiederum die Listenlänge gespeichert wird, fällt damit auch die Komplexität der
Bestimmung des Eingangsgrades auf O(|V |).)
Adjazenzmatrix Zur Bestimmung des Ausgangs-(bzw. Eingangs-)grades eines Knotens müssen alle
Einträge in der Zeile (bzw. Spalte) dieses Knoten aufsummiert werden.
Es gibt |V | solche Einträge.
2
Damit ergibt sich über alle Knoten eine Komplexität von O |V | .
Aufgabe 3
(Algorithmenentwurf, 4 Punkte)
Ein gerichteter Graph G = (V, E) heißt einzeln zusammenhängend, wenn es für alle Knoten u, v ∈ V
höchstens einen Pfad von u nach v gibt. Geben Sie einen effizienten Algorithmus an, der bestimmt, ob
ein gerichteter Graph einzeln zusammenhängend ist.
Musterlösung:
Zunächst sei angemerkt, dass ein einzeln zusammenhängender Graph per Definition immer azyklisch
sein muss: Gibt es einen Kreis, so gibt es für jeden Knoten v auf dem Kreis und jeden k ∈ N je einen
Pfad, der den Kreis k-fach abläuft. Somit gibt es beliebig viele Pfade von v nach v, was der Definition
widerspricht.
Der Algorithmus startet auf jedem Knoten des Graphen eine Tiefensuche. Der Graph ist einzeln
zusammenhängend, wenn es in jeder der Tiefensuchen nur Baum- und keine Quer-, Rückwärts- oder
Vorwärtskanten gibt.
Beweis: Zunächst zeigen wir, dass G azyklisch sein muss, wenn der Algorithmus ausgibt, dass G einzeln
zusammenhängend ist. Wir nehmen also an, dass G einen Kreis enthält. Betrachten wir eine Tiefensuche,
die auf einem Knoten u des Kreises gestartet wurde. Klar ist, dass diese Tiefensuche irgendwann die
Kante betrachtet, die den Kreis schließt, also eine Kante (v, u), wobei v der Knoten ist, der auf dem
Kreis vor u liegt. Da u aber die Wurzel der Tiefensuche ist, ist diese Kante klar eine Rückwärtskante
und der Algorithmus bricht ab.
Wir zeigen nun zunächst, dass der Algorithmus immer mit „nicht einzeln zusammenhängend“ abbricht,
wenn der Graph nicht einzeln zusammenhängend ist. Angenommen, es gibt zwei Knoten u und w,
und zwei Pfade P = hu, v1 , v2 , . . . , wi und P 0 = hu, v10 , v20 , . . . , wi mit P 6= P 0 . Betrachten wir nun die
Tiefensuche, die in u startet. O.b.d.A. nehmen wir an, dass der Pfad P von der Tiefensuche vor dem
Pfad P 0 gefunden wurde. Sei e = (a, b) die erste Kante in P 0 , in der P und P 0 sich unterscheiden. Falls b
in P ist, so ist e eine Vorwärtskante und der Algorithmus bricht ab. Falls b nicht in P ist, so beginnt in
b ein Teilpfad P̃ = hb1 , . . . , bk i von P 0 , der nicht zu P gehört, aber irgendwann (spätestens in w) wieder
mit P zusammenlaufen muss. Die Tiefensuche exploriert also P̃ und stößt irgendwann auf eine Kante,
die wieder zu P führt. Diese Kante ist eine Querkante und der Algorithmus bricht ab.
Wir müssen nun noch zeigen, dass keine der Tiefensuchen eine Quer-, Rückwärts- oder Vorwärtskante
findet, wenn der Graph einzeln zusammenhängend ist.
Rückwärtskanten Sei e = (u, v) eine Rückwärtskante. Dann gibt es also einen Pfad P von v nach u,
und somit schließt e einen Kreis.
Vorwärtskanten Sei e = (u, v) eine Vorwärtskante. Dann gibt es einen Pfad P von u nach v, der
nicht über e verläuft und damit zusammen mit e insgesamt mindestens zwei Pfade.
Querkanten Sei e = (u, v) eine Querkante in einer Tiefensuche, die in w gestartet wurde. Dann gibt
es einen Pfad P1 von w nach u und einen Pfad P2 von w nach v. Indem man zunächst P1 und
dann e abläuft ergibt sich ein weiterer, von P2 verschiedenen Pfad von w nach v.
Somit arbeitet der Algorithmus korrekt.
Es müssen |V | Tiefensuchen ausgeführt werden. Die Laufzeit des Algorithmus ist damit O(|V | · (|V | + |E|)).
3
Aufgabe 4
(Doktor Meta, 4 Punkte)
Der ebenso geniale wie fundamental fehlentworfene Robotergehilfe und Untersuperbösewicht Røbøt hat
sich auf dem Weg zu Doktor Metas geheimer Basis in den Tunnelsystemen unter Karlsruhe verlaufen.
Bei sich hat er nur eine große Menge von 1-Cent-Stücken, die er ursprünglich als Beute bei Doktor Meta
abliefern wollte.
Modellieren Sie das Tunnelsystem als ungerichteten Graphen G = (V, E). Dabei entsprechen Kreuzungen
den Knoten in V und Tunnelabschnitten zwischen Kreuzungen den Kanten. Entwerfen Sie einen
Algorithmus der in Zeit O(|V | + |E|) einen Pfad berechnet, der jede Kante in E in beide Richtungen
genau je einmal traversiert.
Wie kann Røbøt mit Hilfe dieses Algorithmus und der Münzen das Hauptquartier von Doktor Meta
finden? Gehen Sie dabei davon aus, dass sich Røbøt zwar den Algorithmus merken kann, sein beschränktes
Gedächtnis aber keine zurückgelegten Wege und offensichtlich keine Karte speichern kann.
Musterlösung:
Hierfür kann eine Variante der Tiefensuche auf G = (V, E) verwendet werden. Wir nehmen den Graph
als zusammenhängend an (sonst kann es so einen Pfad nicht geben). Jede Kante wird dabei bei der
ersten und der zweiten Traversion jeweils mit einer eindeutigen Kennzeichnung versehen. Wie bei der
Tiefensuche werden außerdem bereits besuchte Knoten markiert und sich zu jedem Knoten die Kante
gemerkt, durch die er zum ersten Mal betreten wurde. Der Algorithmus beginnt an einem beliebigen
Knoten und führt von dort eine Tiefensuche auf G aus. Der gesuchte Pfad ergibt sich schließlich aus
der Reihenfolge, in der die Kanten während der Tiefensuche betrachtet werden. Zunächst wird der
Startknoten als besucht markiert und die folgenden Schritte ausgehend vom Startknoten durchgeführt.
1. Abgehend vom aktuellen Knoten wird (falls möglich) eine beliebige unmarkierte Kante {u, v}
betrachtet. Diese Kante wird als einmal besucht markiert.
• Falls v noch nicht markiert ist (und damit zum ersten Mal besucht wird), wird {u, v} als
einmal besucht markiert, als Eingangskante zu v gespeichert und zum Pfad hinzugefügt. v
wird markiert und mit v als aktuellen Knoten wird der erste Schritt wiederholt.
• Falls v als bereits besucht markiert ist, wird {u, v} als zweimal besucht markiert und (diesmal
in umgekehrter Richtung) zum Pfad hinzugefügt. Der erste Schritt wird erneut mit u als
aktuellem Knoten ausgeführt.
2. Falls es keine unmarkierte Kante {u, v} (mehr) gibt, wird u über die Kante {w, u} über die u zum
ersten Mal betreten wurde wieder verlassen. Die Kante {w, u} wird als zweimal besucht markiert
und zum Pfad hinzugefügt. Der erste Schritt wird mit w als aktuellen Knoten wiederholt.
Offensichtlich werden so alle Kanten in jede Richtung höchstens einmal traversiert. Da der Graph
zusammenhängend und nicht gerichtet ist, werden bei der Tiefensuche alle Knoten irgendwann betrachtet
(der Algorithmus kann nicht in eine Sackgasse führen, da jeder Knoten durch die Eingangskante wieder
verlassen werden kann bis schließlich der Startknoten wieder erreicht wird). Da jeder Knoten erneut
besucht wird, solange er benachbart zu unmarkierten Kanten ist (erst wenn alle Kanten markiert sind
kann er endgültig durch den zweiten Schritt verlassen werden), werden auch alle Kanten besucht. Jede
Kante ist außerdem entweder Eingangskante zu einem Knoten und wird daher durch den zweiten Schritt
erneut in umgekehrter Reihenfolge durchlaufen oder wird direkt im ersten Schritt in beide Richtung
durchlaufen. Deshalb werden alle Kanten auch tatsächlich genau einmal in jede Richtung traversiert.
Die Laufzeit der Tiefensuche liegt in O(|V | + |E|).
Røbøt kann einfach von der nächsten Kreuzung beginnen den beschriebenen Algorithmus auszuführen
und abbrechen, sobald er Doktor Metas geheime Basis erreicht hat. Dafür muss er jeden Tunnelabschnitt
höchstens zweimal betreten (wenn er die Markierungen geschickt setzt). Mit Hilfe der Münzen muss er
markieren welche Kreuzungen er bereits besucht hat (dazu kann er z.B. eine Münze in die Mitte der
Kreuzung legen) und durch welchen Tunnelabschnitt er die Kreuzung zum ersten Mal betreten hat (dazu
kann er z.B. zwei übereinandergestapelte Münzen in Richtung dieses Abschnittes legen (ein gedachter
4
Pfeil von der Münze in der Tunnelmitte zu diesem Münzstapel zeigt dann in Richtung des besagten
Tunnelabschnittes). Außerdem muss er markieren welche Kante er zum ersten beziehungsweise zweiten
Mal betreten hat. Da jede Kante (bzw. jeder Tunnelabschnitt) entweder eine Eingangskanten ist (und
damit durch den Münzstapel indirekt als bereits besucht markiert) oder direkt zum zweiten Mal besucht
wird (und Røbøt in diesem Fall einfach den gleichen Tunnelabschnitt zurücklaufen muss), müssen nur
zum zweiten Mal besuchte Kanten explizit markiert werden. Um Laufarbeit zu sparen sollte das nach
dem Zurücklaufen passieren, z.B. durch drei aufeinander gestapelte Münzen am Tunnelabschnittseingang.
5
Herunterladen