Technische Universität München Zentrum Mathematik Prof. Dr. P. Gritzmann, Dipl.-Inf. Dipl.-Math. S. Borgwardt, Dr. M. Ritter Optimierung 2, WS 2008/09 Übungsblatt 10 Aufgabe 10.1 Betrachten Sie das Problem Subset Sum aus Aufgabe 8.2: Problem (Subset Sum) Gegeben: Eine Menge S = {s1 , ..., sn } mit Auftrag: Entscheide, ob eine Teilmenge si ∈ Z ∀i ∈ {1, ..., n}, β ∈ Z. S0 ⊂ S X existiert, so dass x = β. x∈S 0 a) Zeigen Sie, dass Subset Sum in N P b) Geben Sie einen Algorithmus an, der liegt. Subset Sum mit dynamischer Optimierung löst und dazu eine Rückwärtsrekursion verwendet. Beachten Sie den Sonderfall c) Beweisen Sie, dass β = 0! Subset Sum (durch dynamische Optimierung) in pseudo-polynomieller Zeit gelöst werden kann. Lösung zu Aufgabe 10.1 a) Als Zertikat benutzen wir eine gegebene Teilmenge Zeit testen, ob die gegebene Teilmenge sich auf für Subset Sum ist. β S 0 ⊂ S . Wir können in polynomieller aufsummiert und damit eine Lösung b) Bei einer Rückwärtsrekursion bauen wir unseren Entscheidungsschichtgraphen von hinten auf. Wir konstruieren ihn ähnlich wie in der Vorlesung: Jedes Element si ∈ S Vi−1 von Knoten. Die Kanten des Graphen verlaufen jeweils zwi0 schen Schichten Vi−1 , Vi und entsprechen den Entscheidungen, ob si für S benutzt wird oder nicht. Die Knoten in Schicht Vi bezeichnen wir mit vi,j , dabei entspricht j der in den weiteren Schritten notwendigen Restsumme, d. h. für einen Knoten vi,j ist X j=β− sk induziert eine Schicht k≥i+1 sk ∈S 0 Der Index j gibt also an, welche Summe die im Folgenden auszuwählenden Elemente noch haben müssen. Zu einem Element vi,j ∈ Vi unterscheiden wir nun zwei Fälle: 0 Entweder si wird nicht in die Menge S aufgenommen, dann ändert sich beim Übergang 1 Vi nach Vi−1 die Summe j nicht, es gibt also eine Kante zwischen vi−1,j und vi,j . Alternativ wird si in S 0 aufgenommen, dann verringert sich beim Übergang nach Vi−1 die Summe um si , das kennzeichnen wir durch eine Kante zwischen vi−1,j−si und vi,j . Wir beginnen die Rekursion mit einem Knoten t = vn,β und versuchen einen Weg von t nach s = v0,0 durch den Schichtgraphen zu konstruieren, dieser entspricht dann 0 einem geeigneten S . von Schicht Um den Sonderfall β =0 mitbehandeln zu können, müssen wir identizieren ob bzw. ψ so, dass 1 auf den aktuellen Knoten addiert wird. wie viele Elemente wir jeweils für unsere Teilmenge wählen. Dazu setzen wir für jedes benutzte Element aus S ein Wert von α für jeden neu erreichten Knoten des Graphen. β nichtleere Teilmenge geben, so ergibt sich α(s) > 0. Wir wählen dann jeweils ein maximales Wir nden auf diesem Weg die Teilmenge mit den meisten Elementen, die sich auf aufsummiert. Sollte es eine solche In Pseudocode erhalten wir folgenden Algorithmus für • Input: • Output: Subset Sum: S = {s1 , ..., sn }, β α(s) α(s) ≤ 0 ⇒ No-Instance α(s) > 0 ⇒ Yes-Instance • Dene: V = V0 ∪ ... ∪ Vn , where V0 = {s = v0,0 }, Vn = {t = vn,β } and Vi = ∅ otherwise • Initialize: • For α(t) = 0, α(s) = −∞. i ∈ n, ..., 1 For all do vi,j ∈ Vi do ∗ If vi−1,j ∈ / Vi−1 , create vi−1,j , Vi−1 ← Vi−1 ∪{vi−1,j } and set α(vi−1,j ) = −∞. ∗ / Vi−1 , create vi−1,j−si , Vi−1 ← Vi−1 ∪{vi−1,j−si } and set α(vi−1,j−si ) = vi−1,j−si ∈ −∞. If ∗ α(vi−1,j ) = max{α(vi−1,j ), α(vi,j )} ∗ α(vi−1,j−si ) = max{α(vi−1,j−si ), α(vi,j ) + 1} si ,P SN ⊂ S ≤ x. Wir die Teilmenge aller positiven uns Indices ≥ P x∈SN x und n P |si | Knoten: Sei SP ⊂ S i=1 die Teilmenge aller negativen si , dann reichen c) In jeder Schicht unseres Graphen gibt es höchstens Sum := führen die innere Schleife pro Schicht also x∈SP Sum mal aus und erhalten damit eine Sum). Sei M ax := | max x|. Da Sum ≤ nM ax, ist höchstens x∈S also pseudo-polynomiell. (Man beachte jedoch, dass Anzahl von Operationen in O(n · 2 unsere Laufzeit also in O(n M ax), Sum bzw. M ax nicht polynomiell, sondern exponentiell, in der Länge des in Bitdarstellung kodierten Inputs ist.) 2 Aufgabe 10.2 Ein umweltbewuÿter Student möchte zwar weiterhin mit seinem Auto von seinem Wohnheim in München an die TU nach Garching fahren, dabei aber nicht zuviel Benzin verbrauchen. G = (V, E) und zwei Knoten s t (TUM) gegeben. Die Fahrzeiten und den Spritverbrauch je Kante geben zwei Abbildungen l : E → R≥0 und d : E → N0 (Spritverbrauch fällt nur in ganzzahligen Einheiten an). Der Student möchte für seine Fahrten einen Gesamtverbrauch von D ∈ N Die möglichen Verbindungen seien durch einen Digraphen (Studentenwohnung) und (einfache Fahrt) nicht überschreiten. s-t-Weg ohne Beachtung a) Bestimmen Sie in dem untenstehenden Graphen den kürzesten des Verbrauchs. Welchen Spritverbrauch erfordert dieser Weg? b) Sei ξj (δ) die Länge eines kürzesten s-j -Weges, auf dem höchstens verbraucht werden. Formulieren Sie eine Rekursion für die δ Einheiten Sprit ξj (δ). c) Verwenden Sie die Rekursion aus b), um unter Verwendung von dynamischer Optimie- D die Länge eines kürzesten D Liter Sprit verbraucht wer- rung einen Algorithmus zu entwerfen, der für gegebenes s-t-Weges bestimmt, auf dem insgesamt nicht mehr als den. Skizzieren Sie zunächst einen geeigneten Schichtgraphen, denieren Sie Knoten und Kanten dieses Schichtgraphen und eine passende Stufenkostenfunktion. d) Lösen Sie mit Ihrem Algorithmus das Problem auf untenstehendem Graphen für D = 8. e) Wie hoch ist die Laufzeit Ihres Algorithmus? Bestimmen Sie eine möglichst gute obere Schranke in Abhängigkeit von den Gröÿen im Input. 5/3 2/ 1 3/ 2/ 2 2 4/2 7 6 2 6 6/ 5/ 3 2/4 1/3 1 4 2 5/ 4 2/ 3/ 2 2 5 Beschriftung der Kanten: lij /dij Lösung zu Aufgabe 10.2 a) Wir benutzen einen Dijkstra-Algorithmus zur Lösung des Problems, vgl. folgende graphische Darstellung. Als Beschriftung der Knoten verwenden wir hier das jeweilige Knotenlabel ξ(vi ), blaue Knoten sind bereits endgültig gelabelt. 3 2/ 1 2 1 6 3/ 1 1 2/ 6 8 11 6 2 2/ 2/ 2 2/ 2 2/ 6 3/ 11 2 5/ 3/ 2 2/ 2 2/ 2 3/ 2 1 2 2/ 2 6 3/ 1 2/ 2 2 3/ 2/ 1 2 3/ 2 3/ 2/ 2/ 3/ 4/2 2/4 6/ 2 11, 2 2 2 4 2/ 1/3 5/ 4/2 Der kürzeste Weg hat also Länge 5/ 5 7 5 4 7 6/ 5/ 2 2 0 6 3/ 2/4 1/3 2/4 6/ 5/ 5/3 ∞ 8 5/3 4 3 beträgt 4/2 4 2 4 1/3 0 2 5 2/ 5/ 2/ 3/ 3 5/ 2 2 7 8 7 2/4 5/ 2 4 12 ∞ 5/3 8 5 4/2 4/2 ∞ 6/ 6 2 4 0 3/ 6/ 1/3 2/4 ∞ 5/ 2 2/4 3 6/ 2 5/3 4 8 2 8 5 2/ 4 5/ 4 4 5/ 4/2 3 0 ∞ 5 4 2/ 2/ 1/3 0 1/3 5/3 3 2 2 4/2 5 0 5/ 2 6/ 2 5/ 2/ ∞ 2/4 ∞ 1/3 0 2 5/ 2/ 4 5/3 3 3/ ∞ 3/ 5/3 3 8 der Spritverbrauch entlang des kürzesten Weges 2 + 3 + 2 + 6 = 13. b) Bei einem Gesamtbudget von D überschritten wird, also setzen wir eignet sich ξs (0) = 0. bricht die Rekursion immer ab, wenn das Budget ξj (δ) = ∞ für alle δ > D. Als Beginn der Rekursion Für die Rekursion verwenden wir ξj (δ) := min ξj (δ − 1), min [ξk (δ − δkj ) + lkj ] k∈N (j) 4 Der Schichtgraph kann dann wie folgt deniert werden: In Schicht Knoten v0,s,0 entspricht also Knoten Vk−1 Wenn Schicht Schicht Vk 0 bendet sich der v0,s,0 von 0). (wir indizieren immer mit Schicht,Knoten,gesamter Spritverbrauch, s in Schicht V0 bei einem bisherigen Gesamtverbrauch vk−1,i,δ enthält, so nehmen wir in 0 auf mit j ∈ N (i), für die δ ≥ δ + dij gilt. Der Schichtgraph bekannt ist und einen Knoten alle Knoten vk,j,δ0 entspricht also im Wesentlichen dem fürs Kürzeste-Wege-Problem, wir nehmen aber zusätzlich eine Kopie jedes Knotens für jeden möglichen Gesamtverbrauch in die Schichten mit auf. Eine Kante kennzeichnet jeweils alle möglichen Übergänge von einer Schicht in die nächste, d. h. eine Kante (vk−1,i,δ , vk,j,δ 0 ) existiert genau dann, wenn (i, j) ∈ E und δ 0 ≥ δ + dij . Die Stufenkostenfunktion ψk denieren wir als ψ(vk−1,i,δ , (vk−1,i,δ , vk,j,δ0 )) := lij . In der letzten Schicht k ∗ benötigen wir dann Knoten für den Originalknoten t ∈ V und für jeden zulässigen Gesamtverbrauch, also z.B. alle Knoten vk∗ ,t,δ mit 0 ≤ δ ≤ D. c) Der Algorithmus, der sich aus dem oben skizzierten dynamischen Programm ergibt, kann als Abwandlung des Dijkstra-Algorithmus verstanden werden. Im Unterschied zu diesem benötigen wir jetzt nicht mehr ein Label (das beim Dijkstra-Algorithmus die Länge eines kürzesten s-j -Weges für jeden Knoten j∈V angibt), sondern wir benutzen ein Label für jeden möglichen Spritverbrauch (das entspricht dem dritten Index der D+1 Knoten im Schichtgraphen). Wir benutzen also eine Abbildung x : V → R , xv = T (ξv (0), ξv (1), . . . , ξv (D)) . Das Update der Label im Dijkstra-Algorithmus führen wir unter Berücksichtigung des jeweiligen Kantenverbrauchs durch. Es ergibt sich damit Algorithmus 1. Algorithm 1: Dijkstra-Variante für Constrained Shortest Path Input: Digraph G = (V, E) mit Kantenbewertungen l, d : E → R≥0 , eine natürliche Zahl D ∈ N0 und s∈V. Output: Die Längen xv = (ξv (0), ξv (1), . . . , ξv (D))T Verbrauch in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0, 1, . . . , D und jeden Knoten S ← {(s, 0), . . . , (s, D)}, xs ← 0 · 1, xv ← ∞ · 1 for v ∈ N (G, s) do for δ = dsv , . . . , D do ξv (δ) ← lsv end end while es gibt (v, δ) ∈ V × {0, . . . , D} \ S ∗ ∗ mit eines kürzesten für jeden v ∈V. für alle v ∈ V \ {s} ξv (δ) 6= ∞ do v ∈ V , δ ∈ {0, . . . , D}, so dass = min {ξv (δ) : (v, δ) ∈ V × {0, . . . , D} \ S} 0 ∗ das ξv ∗ (δ ) = ξv ∗ (δ ). ∗ for v ∈ N (G, v ) do for δ ∈ {δ ∗ + dv∗ ,v , . . . , D} do ξv (δ) ← min {ξv (δ), ξv∗ (δ ∗ ) + lv∗ ,v } Wähle ξv∗ (δ ∗ ) s-v -Weges end end S ← S ∪ {(v ∗ , δ ∗ )} end 5 und so, dass es kein δ0 < δ∗ gibt, für d) Wir stellen die Lösung wieder graphisch dar, endgültige Label sind blau gezeichnet. Die Label stehen jeweils in den Knoten und sind in der Form ξv (0), . . . , ξv (8) zu lesen. Auÿerdem fassen wir mehrere gleiche Schritte zu einem einzigen zusammen. Beachte: Es gibt mehrere reine Labelling-Schritte, bei denen keine tatsächliche Verbesserung mehr stattndet. Das kann im Dijkstra-Algorithmus natürlich auch passieren, hier fällt es aber stärker auf. ∞, ∞, 3, 3, 3, 3, 3, 3, 3 3/ 2/ 2 5/ 6/ 2 5/3 5/3 ∞, ∞, ∞, ∞, ∞, 8, 8, 8, 8 5/ 1 6/ ∞, ∞, 5, 5, 5, 4, 4, 4, 4 2 4/2 6 2/4 1/3 ∞, ∞, ∞, ∞, 7, 7, 5, 5, 5 2 6 ∞, ∞, ∞, ∞, ∞, ∞, ∞, 8, 8 2/ 4 2/ 2/4 1/3 4/2 2 ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ 3/ 2 2/ 2 5/ 1 2/ 6/ ∞, ∞, 3, 3, 3, 3, 3, 3, 3 5/ ∞, ∞, ∞, ∞, ∞, 8, 8, 8, 8 2 ∞, ∞, 5, 5, 5, 4, 4, 4, 4 2 6 ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ ∞, ∞, ∞, ∞, ∞, ∞, 5, 5, 5 2/ 2/4 1/3 4/2 ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ 3/ 2 4 2 2 6/ 2 5/ 5/ 2/ 2/ 0, 0, 0, 0, 0, 0, 0, 0, 0 ∞, ∞, ∞, ∞, ∞, 8, 8, 8, 8 2/ ∞, ∞, 3, 3, 3, 3, 3, 3, 3 0, 0, 0, 0, 0, 0, 0, 0, 0 ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ ∞, ∞, ∞, ∞, ∞, ∞, 5, 5, 5 2 3/ 1 4 ∞, ∞, 5, 5, 5, 4, 4, 4, 4 3/ 5/3 2/ 2 2 3/ 4/2 ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ 6 2 ∞, ∞, 3, 3, 3, 3, 3, 3, 3 5/ 2 ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ ∞, ∞, 5, 5, 5, 5, 5, 5, 5 0, 0, 0, 0, 0, 0, 0, 0, 0 5/ 1 2/ 4 2/ 2 3/ ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ 2/4 1/3 0, 0, 0, 0, 0, 0, 0, 0, 0 5/3 2 ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ 3/ 6 ∞, ∞, ∞, ∞, 9, 9, 9, 8, 8 ∞, ∞, 3, 3, 3, 3, 3, 3, 3 2/ 2 5/ 2 ∞, ∞, ∞, ∞, 7, 7, 5, 5, 5 6/ 2 2/ ∞, ∞, 3, 3, 3, 3, 3, 3, 3 4/2 5/3 5/ 1 4/2 5/3 6 ∞, ∞, ∞, ∞, 9, 9, 9, 8, 8 ∞, ∞, ∞, ∞, ∞, 8, 8, 7, 7 5/ 1 6/ 2 4/2 7 2/4 1/3 ∞, ∞, ∞, ∞, 7, 7, 5, 5, 5 ∞, ∞, 5, 5, 5, 4, 4, 4, 4 ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ 2/ 2 2 3/ 2 4 2/ 2/4 1/3 6/ 2 2/ 2 ∞, ∞, ∞, ∞, ∞, 8, 8, 7, 7 2/ 2 5/ ∞, ∞, ∞, ∞, 9, 9, 9, 8, 8 ∞, ∞, ∞, ∞, 7, 7, 5, 5, 5 ∞, ∞, 3, 3, 3, 3, 3, 3, 3 6 2/ 4 ∞, ∞, 5, 5, 5, 4, 4, 4, 4 ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ 3/ 2 2/ 2 0, 0, 0, 0, 0, 0, 0, 0, 0 2 6/ ∞, ∞, 3, 3, 3, 3, 3, 3, 3 2 5/ 1 2 2/ 5/ ∞, ∞, ∞, ∞, ∞, 8, 8, 7, 7 ∞, ∞, ∞, ∞, 7, 7, 5, 5, 5 ∞, ∞, 5, 5, 5, 4, 4, 4, 4 0, 0, 0, 0, 0, 0, 0, 0, 0 ∞, ∞, ∞, ∞, 9, 9, 9, 8, 8 2/4 1/3 2 6 2/ 4 5/ 3/ 5/3 2/ 2 3/ 4/2 2 ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞, ∞ 3/ 2 ∞, ∞, 5, 5, 5, 4, 4, 4, 4 0, 0, 0, 0, 0, 0, 0, 0, 0 5/ 2/ 2/4 1/3 0, 0, 0, 0, 0, 0, 0, 0, 0 ∞, ∞, ∞, ∞, ∞, 8, 8, 7, 7 1 4 3/ 3/ 5/3 2 ∞, ∞, ∞, ∞, ∞, ∞, ∞, 13, 13 6 3/ ∞, ∞, ∞, ∞, 9, 9, 9, 8, 8 5/3 ∞, ∞, 3, 3, 3, 3, 3, 3, 3 2/ 2 2/ 5/ 2 2/ ∞, ∞, ∞, ∞, ∞, 8, 8, 7, 7 2/ 2/ 2 4/2 hat also Länge e) Die Laufzeit des Algorithmus liegt in 2 ∞, ∞, ∞, ∞, ∞, ∞, ∞, 13, 13 6/ 2 ∞, ∞, 5, 5, 5, 4, 4, 4, 4 D=8 2/4 1/3 ∞, ∞, ∞, ∞, 7, 7, 5, 5, 5 2 Der kürzeste Weg bei 5/ 1 2/ 4 5/ 3/ ∞, ∞, ∞, ∞, 9, 9, 9, 8, 8 5/3 ∞, ∞, 3, 3, 3, 3, 3, 3, 3 0, 0, 0, 0, 0, 0, 0, 0, 0 6 2 4/2 2 ∞, ∞, ∞, ∞, ∞, ∞, ∞, 13, 13 6/ 2 ∞, ∞, 5, 5, 5, 4, 4, 4, 4 2 2/4 ∞, ∞, ∞, ∞, 7, 7, 5, 5, 5 1/3 0, 0, 0, 0, 0, 0, 0, 0, 0 5/ 1 4 3/ 3/ ∞, ∞, ∞, ∞, ∞, 8, 8, 7, 7 6 3/ ∞, ∞, ∞, ∞, 9, 9, 9, 8, 8 13. O(n2 D). Die Updates funktionieren im Grunde genauso wie im Dijkstra-Algorithmus, müssen aber für jedes der bis zu D Label durch- geführt werden, damit ist der Algorithmus nur noch pseudopolynomiell (da sich Codierungslänge O(log2 D) D mit codieren lässt). Wenn man den Dijkstra-Teil geschickt im- plementiert (z. B. die Labels in einem entsprechend angepassten Heap verwaltet), lässt 2 sich diese Schranke noch ein wenig verbessern (genauer gesagt, der n -Anteil), pseudopolynomiell bleibt sie aber trotzdem. Aufgabe 10.3 Hausaufgabe Gegeben sei der Graph G = (V, E, c) e1 e4 e7 e10 und = (v1 , v2 ), = (v2 , v4 ), = (v4 , v7 ), = (v5 , v6 ), mit V = {v1 , . . . , v8 }, E = {e1 , . . . , e12 }, e2 = (v1 , v3 ), e5 = (v3 , v6 ), e8 = (v4 , v8 ), e11 = (v6 , v7 ), wobei e3 = (v1 , v5 ), e6 = (v3 , v8 ), e9 = (v5 , v2 ), e12 = (v7 , v8 ), (c(e1 ), . . . , c(e12 )) = (28, 2, 1, 9, 24, 27, 8, 7, 8, 26, 8, 7). Berechnen Sie mit Hilfe des Dijkstra-Algorithmus den kürzesten Weg zwischen den Ecken und v8 . Skizzieren Sie jeden Zwischenschritt grasch! 8 v1 8 27 2 24 3 6 8 26 1 28 8 2 9 4 Lösung zu Aufgabe 10.3 9 7 7 1 5 7 8 10 11