Prof. Dr. Peter Sanders Dennis Luxen, Dr. Johannes Singler Karlsruher Institut für Technologie Institut für Theoretische Informatik 3. Übungsblatt zu Algorithmen II im WS 2010/2011 http://algo2.iti.kit.edu/AlgorithmenII.php {luxen,sanders,singler}@kit.edu Musterlösungen Aufgabe 1 (Theoretische Überlegungen zu Maximalen Flüssen) Sei G = (V, E) ein gerichteter Graph, in dem maximale Flüsse berechnet werden sollen. a) Zeigen Sie: Falls eine Kante (i, j) ∈ E für jeden maximalen Fluss voll ausgelastet ist, dann führt diese Kante aus einem minimalen Schnitt heraus. b) Sei e = (i, j) ∈ E genauso wie e0 = (j, i) ∈ E, d. h. G besitzt ein Paar entgegengesetzter Kanten. Außerdem sei c(e) ≥ c(e0 ) Widerlegen Sie durch ein Gegenbeispiel: Wenn man e0 aus E entfernt und c(e) := c(e) − c(e0 ) reduziert, ändert sich der maximale Fluss nicht, d. h. man kann entgegengesetzte Kanten a-priori (für beliebige s und t) gegeneinander aufrechnen. c) Analog zur Beschränkung des Flusses durch eine Kante kann man auch den Durchfluss durch einen Knoten begrenzen. Jedem Knoten v wird dazu eine Knotenkapazität cap(v) zugeordnet. Die Summe der eingehenden bzw. ausgehenden Flüsse darf cap(v) nicht überschreiten. Erklären Sie, wie maximale Flüsse mit Knotenkapazitäten berechnet werden können. Begründen Sie kurz, warum Ihr Algorithmus einen zulässigen und optimalen Fluss berechnet. (Klausuraufgabe Algorithmentechnik WS 2007/2008) Werden durch die Transformation Flüsse unmöglich, die vorher möglich waren? Wieso ist das nicht schlimm? Musterlösung: a) F sei der Wert eines maximalen Flusses, also auch aller anderen. Wir entfernen (i, j) mit Kapazität uij . Alle maximalen Flüsse verringern sich dadurch um genau uij , sind jetzt also F − uij . Nun bestimmen wir einen maximalen Fluss mit minimalem Schnitt S. Dann gilt j ∈ / S, j ist im Restnetzwerk von s aus nicht mehr zu erreichen, denn sonst gäbe es einen augmentierenden Pfad von s über j nach t, denn auf dem Pfad zwischen j und t ist die Kapazität uij gerade frei geworden. i ist in S, weil es jetzt wieder eine Restkapazität von uij von s nach i gibt. Fügen wir jetzt (i, j) wieder ein. Zu zeigen: S ist immer noch ein minimaler Schnitt, jetzt wieder für den kompletten Graphen. Beweis: Im Restnetzwerk ist j (und damit auch t) jetzt nur wieder über (i, j) zu erreichen. Also geht aller zusätzliche Fluss von uij wieder über (i, j). Wenn wir (i, j) jetzt wieder voll auslasten, beträgt die Kapazität den Schnitts wieder F , also ist er minimal. (i, j) führt also aus dem minimalen Schnitt S heraus. b) Rechnet man die Kanten in folgendem Graph gegeneinander auf, 2 j i 5 1 so ergibt sich folgendes: j i 3 Für s := j und t := i ist nun kein Fluss mehr möglich, während im Originalgraphen noch ein maximaler Fluss von 2 möglich war. Dies ist somit ein Gegenbeispiel zur Behauptung. Bei der Berechnung des Maximalen Flusses lassen sich entgegengesetzte Kanten somit nicht durch solch einen Trick vermeiden. c) Wir definieren einen neuen Graph G0 = (V 0 , E 0 ). Für jeden Knoten v in V gibt es zwei Knoten vein und vaus in V 0 . Von vein nach vaus führt jeweils eine Kante mit Kapazität cap(v). Außerdem wird für jede Kante (u, v) ∈ E eine Kante (uaus , vein ) in E 0 eingefügt. (Die Kapazität dieser Kante wird aus G übernommen bzw. auf ∞ gesetzt, falls es dort keine Einschränkungen gab.) Nun berechnet man einen maximalen Fluss von sein nach taus in G0 und transformiert die Flusswerte für die Kanten zurück nach G. Dieser Fluss ist zulässig in G unter Berücksichtigung der Knotenkapazitäten, da der Knotendurchfluss durch die neuen Kanten passend beschränkt wurde. Außerdem ist der Fluss optimal, denn gäbe es noch einen augmentierenden Pfad in G unter Berücksichtigung der Knotenkapazitäten, so ebenfalls in G0 : Die Restkapazitäten der ursprünglichen Kanten sind per Definition gleich, eine zu einem nicht voll ausgelasteten Knoten gehörende neue Kante hätte ebenfalls noch Restkapazität, alle Pfade sind weiterhin vorhanden. Wenn man entgegengesetzte Kanten hat, und das Minimum beider Flüsse jeweils als abgezogen und nicht durch den Knoten geflossen betrachtet, so gäbe es (maximale) Flüsse, die im transformierten Graphen nicht möglich sind. Allerdings hat ein anderer Fluss mindestens den gleichen Flusswert. Aufgabe 2 (Beispiel rechnen zu Highest-Level-Preflow-Push) Führen Sie für folgenden Graphen den Highest-Level-Preflow-Push-Algorithmus aus, um den maximalen Fluss von s nach t zu finden, bis insgesamt fünf Mal relabel aufgerufen wurde. Wenn es mehrere Knoten bzw. Zielknoten zur Auswahl gibt, geben Sie in alphabetischer Reihenfolge vor. c d 8 10 10 4 a 30 20 5 25 s t 5 15 5 9 b 6 e Musterlösung: Legende inactive active d excess flow residual cap capcacity d excess residual cap 2 Initialisierung c 0 10 d 00 8 4 10 10 0 1 0 10 t 00 5 30 5 25 s a 7 -45 20 0 20 0 20 20 15 15 0 1 5 b 0 15 5 9 e 00 6 Relabel a, d∗ = 1 c 0 10 d 00 8 4 10 10 0 1 0 10 30 5 25 s a 7 -45 20 0 20 1 20 20 15 0 15 1 5 b 0 15 9 5 4 5 t 00 5 e 00 6 9 Push a → c; Push a → d; Push a → e t 00 5 30 a 12 10 5 5 05 5 25 s 7 -45 20 0 20 20 15 15 0 1 5 b 0 15 d 05 8 4 4 40 10 10 0 1 0 c 0 14 90 9 9 6 3 e 09 Relabel a, d∗ = 8 10 t 00 5 5 05 a 82 30 5 25 90 9 9 5 s 7 -45 20 0 20 20 15 15 0 1 5 b 0 15 d 05 8 4 4 40 10 10 0 1 0 c 0 14 e 09 6 2 Push a → s 10 t 00 5 5 05 a 80 30 5 25 90 9 9 5 s 7 -43 18 2 20 18 15 15 0 1 5 b 0 15 d 05 8 4 4 40 10 10 0 1 0 c 0 14 e 09 6 Relabel b, d∗ = 1 5 10 10 0 1 t 00 30 a 80 10 5 5 05 5 25 s 7 -43 18 2 20 18 15 15 0 1 5 b 1 15 d 05 8 4 4 40 0 c 0 14 90 9 9 6 4 e 09 6 Push b → e c 0 14 10 t 00 5 5 05 30 5 25 a 80 90 9 9 5 10 10 0 1 0 4 4 40 s 7 -43 18 2 20 18 15 15 0 1 5 b 19 d 05 8 e 0 15 606 6 Relabel b c 0 14 10 t 00 5 5 05 30 5 25 a 80 90 9 9 5 10 10 0 1 0 4 4 40 s 7 -43 18 2 20 18 15 15 0 1 5 b 89 d 05 8 e 0 15 606 6 9 Push b → s c 0 14 5 6 9 6 15 a 80 b 80 t 00 5 25 18 2 20 18 10 5 5 05 30 10 10 0 1 0 4 4 40 s 7 -34 d 05 8 90 9 9 606 6 5 e 0 15 Relabel c c 1 14 5 6 9 6 15 b 80 Aufgabe 3 I SS 2009 ) a 80 t 00 5 25 18 2 20 18 10 5 5 05 30 10 10 0 1 0 4 4 40 s 7 -34 d 05 8 90 9 9 606 6 e 0 15 (Blockweises Hashing und Maximale Flüsse, vgl. Programmieraufgabe 2 in Algorithmen Bei blockbasiertem Hashing mit zwei Hashfunktionen enthält ein Eintrag der Hash-Tabelle nicht ein einzelnes Element, sondern einen Block für B Elemente. Außerdem müssen zwei unabhängige HashFunktionen h0 und h1 gegeben sein, die einen Schlüssel eines Elements auf einen der m Einträge (Blöcke) der Hash-Tabelle abbilden. Ein Element muss sich entweder in dem durch h0 oder h1 zugewiesenen Block befinden. find muss also nur zwei Blöcke durchsuchen und ist garantiert in konstanter Zeit ausführbar, falls auch B konstant ist. Im Gegensatz zu Cuckoo-Hashing findet keine Verdrängung von Elementen statt. Das Problem ist das Erstellen einer gültigen Hashtabelle mit hohem Füllgrad. Wie kann für einen gegebene Menge S von n Elementen bestimmt werden, ob diese bei optimaler Wahl der Positionen alle gleichzeitig in die Hashtable der Größe m passen? Verwenden Sie dazu maximale Flüsse, und konstruieren Sie einen Flussgraphen für gegebenes S, B und m sowie die Hash-Funktionen h1 und h2 . Wie kann aus dem maximalen Fluss auf die Wahl der Hashfunktion für jedes Element geschlossen werden? Beweisen Sie, dass es genau dann einen maximalen Fluss eines gewissen Werts gibt, wenn die Verteilung erfüllt werden kann. Es gilt im übrigen: Hat der Graph nur ganzzahlige Kantenkapazitäten, so existiert ein maximaler Fluss, bei dem jeden Kante ganzzahligem Fluss leitet. Musterlösung: Für jedes Element si ∈ S gibt es einen entsprechenden Knoten, der eine eingehende Kante von s mit Kapazität 1 besitzt. Für jeden Block bi der Hashtabelle gibt es ebenfalls einen entsprechenden Knoten, der eine ausgehende Kante nach t mit Kapazität B hat. Für jedes s gibt es zusätzlich zwei Kanten zu bh1 (s) bzw. bh2 (s) mit Kapazität 1. 6 sn 1 bm .. . 1( 1 h0 B ) (h 1( 1) s 1 1 s1 h 1) .. . t ) (h 0 b1 B B 1 1 (h ) 0 ) 1 (h 1 b0 s0 Auf diesem Graphen wird nun ein maximaler ganzzahliger Fluss von s nach t berechnet. Hat dieser den Wert n, so existiert eine realisierbare Zuteilung der Elemente in die Blöcke der Hashtabelle. Beweis: Ein Gesamtfluss von n bedeutet einen Fluss von 1 für jede Kante (s, si ). Da die Flüsse der folgenden Kanten ganzzahlig sind, bleiben also nur 0 oder 1. Damit hat jeder Knoten si eine ausgehenden Kante mit Fluss 1, die andere mit Fluss 0. Erstere bestimmt, in welchen Block si gelegt wird. Da aus keinem Block bi mehr als Fluss B wieder abfließen kann, sind keine Blocks überfüllt. Die Elemente aus S können also tatsächlich verteilt werden, ohne Regeln zu verletzen. Gibt es eine regelgerechte Verteilung der Elemente auf die Hashtabelle, so existiert offensichtlich auch ein entsprechender Fluss, der alle Kapazitäten einhält. 7