Eidgenössische Technische Hochschule Zürich Ecole polytechnique fédérale de Zurich Politecnico federale di Zurigo Federal Institute of Technology at Zurich Institut für Theoretische Informatik Peter Widmayer Tobias Pröger Thomas Tschager 13. Mai 2015 Datenstrukturen & Algorithmen Lösung 11.1 Lösungen zu Blatt 11 FS 15 Pfadplanung in Labyrinthen. a) Wir definieren einen gerichteten Graphen, der einen Knoten für jeden möglichen Zustand des Systems enthält. Ein Zustand wird vollständig durch drei Parameter festgelegt: 1) Das Feld auf dem der Roboter steht, 2) die Blickrichtung des Roboters und 3) ob der Roboter gerade steht oder in Bewegung ist. Für jedes Feld, auf dem der Roboter stehen kann, haben wir also 8 Zustände (4 Blickrichtungen multipliziert mit 2 Möglichkeiten ob der Roboter steht oder sich bewegt). Wir konstruieren unseren Graphen entsprechend mit 8 Knoten pro Feld des Labyrinths. Ausserdem brauchen wir noch einen Knoten, der dem Zielzustand entspricht, in dem der Roboter entkommen ist. Wir fügen Kanten für Bewegung, Rotation und Stehenbleiben ein und gewichten diese entsprechend der Zeit, die die entsprechende Operation benötigt. Der kürzeste Pfad im Graphen vom Startzustand des Roboters zum Zielzustand entspricht einer Folge von Operationen des Roboters, die ihn schnellstmöglich entkommen lässt. Das folgende Bild illustriert unsere Konstruktion an einem kleinen Ausschnitt eines Labyrinths. Die Beschriftung der Knoten zeigt die Blickrichtung des Roboters; Doppelpfeile bedeuten, dass er in Bewegung ist. Wir könnten natürlich Zustände entfernen, die gar nicht vorkommen können. 3 2 3 2 2 2 2 2 2 3 3 2 b) Da der konstruierte Graph keine negativen Kantengewichte enthält, kann ein kürzester Pfad mithilfe des Algorithmus von Dijkstra gefunden werden. c) Für jedes Feld des Labyrinths wird eine konstante Anzahl Knoten (nämlich 8) und eine konstante Anzahl Kanten (höchstens 20) verwendet. Ist n die Anzahl der Felder im Labyrinth, dann sind |V | ∈ O(n) und |E| ∈ O(n), also ist die Laufzeit des Algorithmus von Dijkstra durch O(n log n) beschränkt. Anmerkung: Für einen gerichteten, ungewichteten Graph kann ein kürzester Pfad auch mit einer Breitensuche gefunden werden. Da unser Graph nur ganzzahlige Kantengewichte hat, die alle größer als 0 und durch eine Konstante nach oben beschränkt sind, können wir einen erweiterten, ungewichteten Graphen konstruieren, indem wir eine Kante mit Gewicht w > 1 durch w Kanten mit je Gewicht 1 ersetzen. Dazu fügen wir w − 1 Hilfsknoten ein. Hat diese Kante in unserem ursprünglichen Graph einen Knoten x, der mit einem Knoten y verbunden ist, so sind diese Knoten im erweiterten Graph durch einen Pfad bestehend aus w Kanten verbunden. Somit haben im erweiterten Graph alle Kanten Gewicht 1 und wir können die Breitensuche verwenden, um einen kürzesten Pfad zu finden. Da die Kantengewichte durch eine Konstante nach oben beschränkt sind, werden insgesamt nur O(n) Knoten und Kanten hinzugefügt und die Laufzeit ist in O(n). Lösung 11.2 Max-Flow von Hand. Der maximale Flusswert beträgt 31. In der folgenden Abbildung ist ein maximaler Fluss dargestellt. Neben jeder Kante e sind die Kapazität ce und der Flusswert xe in der Reihenfolge xe , ce angegeben. Der minimale Schnitt ist gestrichelt eingezeichnet, und die zugehörigen Kanten sind fett dargestellt. Die folgende Abbildung zeigt den Restgraphen für den oben dargestellten Fluss. An den Kanten ist die jeweilige Restkapazität (ce − xe oder xe ) notiert. Lösung 11.3 Evakuierungsprobleme. a) Sei G = (VG , EG ) das ungerichtete Gitter, das als Eingabe gegeben ist. Die Knotenmenge V des Netzes N enthält neben allen Knoten aus G zusätzlich noch eine Quelle s und eine Senke t. Die Kantenmenge von N enthält nun die folgenden Kanten: • Für jeden Startknoten si enthält N die Kante (s, si ). 2 • Für jede (ungerichtete) Kante {v, w} ∈ EG des Gitters enthält N die zwei gerichteten Kanten (v, w) und (w, v). • Für jeden Randpunkt rj enthält N die Kante (rj , t). Wir konstruieren also ein Netz N = (V, E, c) mit V := VG ∪· {s} ∪· {t} (1) E := {(s, si ) | i ∈ {1, . . . , m}} ∪· {(v, w), (w, v) | {v, w} ∈ EG } ∪· (2) {(rj , t) | rj ist Randpunkt von G} c((s, si )) := 1 ∀i ∈ {1, . . . , m} (3) c((v, w)) := 1 ∀{v, w} ∈ EG (4) c((rj , t)) := 2 ∀ Randpunkte rj (5) Man beachte, dass ein Randpunkt doppelt benutzt werden kann. Einerseits kann er der letzte Knoten eines Fluchtwegs sein, der im Inneren des Gitters startet. Andererseits kann es aber auch einen Fluchtweg geben, der nur aus genau diesem Randpunkt besteht. Aus diesem Grund muss als Kapazität der Kanten (rj , t) genau 2 gewählt werden (und nicht 1). Es gibt nun in G genau dann m kanten-disjunkte Fluchtwege, falls es im obigen Netz N einen Fluss mit Wert mindestens m gibt. b) Wir analysieren zunächst die Grösse des Netzes in Abhängigkeit von n. Das Gitter G hat |VG | = n2 viele Knoten, also ist |V | = 2 + |VG | ∈ Θ(n2 ). Ausserdem hat G genau |EG | = 2n(n−1) ≤ 2n2 viele Kanten und 2n+2(n−2) = 4n−4 viele Randpunkte. Da jede Kante von G in N doppelt vorkommt, ist |E| = m+2|EG |+4n−4 ≤ n2 +4n2 +4n ∈ Θ(n2 ). Der Wert eines Flusses ist sowohl durch m (die Anzahl der Startknoten) als auch durch 8n − 8 nach oben beschränkt, da es nur 4n − 4 Randpunkte gibt und wie oben gesehen maximal zwei Fluchtwege in einem gemeinsamen Randpunkt enden können (theoretisch wären mehr Fluchtwege möglich, aber jeder weitere besucht mindestens einen weiteren Randknoten und muss daher nicht berücksichtigt werden). Der Algorithmus von Ford und Fulkerson berechnet einen maximalen Fluss mit O(|E| · φ∗ ) Operationen, wenn φ∗ der maximale Flusswert ist. Damit ist seine Laufzeit pseudopolynomiell, und im Allgemeinen existieren effizientere Methoden zur Flussmaximierung. Da aber hier |E| ∈ Θ(n2 ) als auch φ∗ = min{m, 8n − 8} ∈ Θ(min{m, n}) gelten, beträgt die Laufzeit des Algorithmus von Ford und Fulkerson nur O(n2 min{m, n}), und die Wahl dieses Verfahrens ist in diesem speziellen Fall optimal. c) Sei v ∈ VG ein Knoten des Gitters und Γ(v) = {w ∈ VG | {v, w} ∈ EG } die Menge aller Nachbarknoten von v in G. Wir erzeugen nun im Netz N für v ∈ VG genau zwei Knoten v in und v out , die durch die gerichtete Kante (v in , v out ) verbunden werden. Abgesehen von dieser Kante enthält v in nur eingehende und v out nur ausgehende Kanten. Für jeden Nachbar w ∈ Γ(v) erzeugen wir jeweils die Kanten (v out , win ) und (wout , v in ). 3 Für alle Startknoten si erzeugen wir ausgehend von der Quelle s eine Kante (s, sin i ). Ausout serdem erzeugen wir für jeden Randpunkt rj eine Kante (rj , t) zur Senke t. Allen Kanten wird Kapazität 1 zugewiesen. Im Vergleich zu a) wird die Anzahl der Knoten nahezu verdoppelt (nur die Quelle und die Senke werden nicht doppelt angelegt). Pro Knoten v ∈ VG wird dabei nur eine weitere Kante angelegt, nämlich die innere Kante (vin , vout ). Damit sind wie vorher |V | ∈ Θ(n2 ) und |E| ∈ Θ(n2 ), und die Laufzeit verändert sich nicht. 4