ETH Zürich Institut für Theoretische Informatik Prof. Dr. Angelika Steger, Prof. Dr. Thomas Holenstein Ralph Keusch HS 2015 Algorithmen und Komplexität Lösungsvorschlag zu Übungsblatt 6 Lösungsvorschlag zu Aufgabe 1 Wir lösen die Aufgaben, indem wir den minimalen Spannbaum T von G so umbauen, dass ein minimaler Spannbaum T 0 von G 0 entsteht. Wir fassen G 0 auf als G mit einer modifizierten Gewichtsfunktion w0 : G → N. Nach Annahme haben wir w0 (e) < w(e) für die modifizierte Kante e und w0 ( f ) = w( f ) für alle anderen Kanten f . Wenn man e zur Kantenmenge von T hinzufügt, erhält man genau einen Kreis C. Es bezeichne emax die Kante aus C mit dem grösstem Gewicht unter w0 . Dann ist T 0 := T ∪ {e} \ {emax } ein Spannbaum von G, da durch Entfernen einer Kante aus C der Graph wieder kreisfrei wird und zusammenhängend bleibt. (Es ist möglich, dass emax gleich der modifizierten Kante e ist - dann ist T 0 = T.) Lemma 1. T 0 ist ein minimaler Spannbaum von G unter w0 . e irgendein Spannbaum von G. Wir zeigen, dass w0 ( T e ) ≥ w 0 ( T 0 ). Beweis. Sei T e die Kante e nicht enthält, gilt w0 ( T e) = w( T e) ≥ w( T ) = w0 ( T ) = w0 ( T 0 ) + • Wenn T 0 0 0 0 w (emax ) − w (e) ≥ w ( T ) wegen der Annahme, dass T minimaler Spannbaum von G unter w ist und nach Konstruktion von T 0 . e die Kante e enthält, entfernen wir diese und erhalten zwei getrennte Komponenten • Wenn T e von T. Eine der restlichen Kanten von C, nennen wir sie f , verbindet diese Komponenten e1 mit Gewicht w0 ( T e1 ) = w0 ( T e) − w0 (e) + und vervollständigt so einen neuen Spannbaum T e1 ) ≥ w0 ( T ) wegen der Annahme, dass T minimaler Spannw0 ( f ). Wieder haben wir w0 ( T baum von G unter w ist. Es folgt e) = w0 ( T e1 ) − w0 ( f ) + w0 (e) ≥ w0 ( T ) − w0 (emax ) + w0 (e) = w0 ( T 0 ). w0 ( T Algorithmisch lässt sich der Graph T 0 leicht aus T und e konstruieren: Mit Tiefensuche in T ∪ {e} findet man den Kreis C in Zeit O(|V |), und die schwerste Kante emax in C findet man in Zeit O(| E(C )|) = O(|V |). Bemerkung: Die Tiefensuche hat einen Kreis gefunden, wenn sie ausgehend von einem Knoten v auf einen Nachbarn u ∈ Γ(v) mit pred[u] 6= nil stösst. Dann bilden pred[v], pred[ pred[v]], . . . , u den Kreis. Die Laufzeit dieses letzten Schrittes ist maximal O(|V |). Es ist auch möglich mit Breitensuche dasselbe Resultat zu erhalten: Sobald man einen Nachbarn u ∈ Γ(v) mit pred[u] 6= nil findet, folgt man den beiden Pfaden (u, pred[u], pred[ pred[u]], . . . ) und (v, pred[v], pred[ pred[v]], . . . ) (parallel!), um den ersten gemeinsamen Knoten w zu finden. Dann ist (u, pred[u], . . . , w, . . . , pred[v], v) ein Kreis. Lösungsvorschlag zu Aufgabe 2 (a) Die aufsteigend sortierte Liste (1, 2, . . . , n) hat keine Inversionen. Da die Anzahl Inversionen nicht negativ sein kann, ist das minimal. In der absteigend sortierten Liste (n, n − 1, . . . , 1) ist jedes Paar ( ai , a j ) mit i 6= j eine Inversion n·(n−1) Inversionen. Da es nicht mehr Inversionen als solche Paare geben und es gibt somit 2 kann, ist das die maximal mögliche Anzahl. 1 n·(n−1) Paare (b) Der Algorithmus verwendet einen Zähler c, der anfangs 0 ist. Dann geht er alle 2 ( ai , a j ) mit i 6= j durch und prüft für jedes ob es eine Inversion ist. Falls ja, setzt er c := c + 1 und sonst ändert er c nicht. Am Ende wird c ausgegeben. Die Korrektheit ist offensichtlich n·(n−1) und die Laufzeit ist O( 2 ) = O(n2 ). (c) Seien L` := ( a1 , a2 , . . . , ad n e ) die linke und Lr := (b1 , b2 , . . . , bb n c ) die rechte Hälfte der Liste 2 2 L, und beide Hälften der Liste seien aufsteigend sortiert. Wir modifizieren den Merge-Schritt von Mergesort, um eine aufsteigend sortierte Liste aller Elemente L0 zu erhalten und gleichzeitig die Anzahl der Inversionen in L zu zählen. Zur Erinnerung: Mergesort verwendet zwei Pointer i für L` und j für Lr . Zu Beginn ist i := 1 und j := 1 und L0 die leere Liste. Falls nun ai < b j ist, wird ai an L0 angehängt und i := i + 1 gesetzt. Andernfalls wird b j an die Liste angehängt und j := j + 1 gesetzt. Dies wird wiederholt, bis alle Elemente in L0 eingeordnet wurden. Wir verwenden nun zusätzlich einen Zähler c, der die Inversionen zählt. Im Fall ai < b j ändern wir c nicht, aber im Fall ai ≥ b j erhöhen wir c um die Anzahl der verbleibenden Elemente in L` , d.h. c := c + ( n2 − i + 1). Korrektheit: Wir argumentieren, dass jede Inversion genau einmal gezählt wird. Immer wenn ein b j an L0 angehängt wird, stellt b j mit allen verbleibenden ak mit k ≥ i eine Inversion dar. Für die ak mit k < i stellt b j keine Inversion dar. Somit werden alle Inversionen in denen b j vorkommt gezählt. Das geschieht für jedes b j genau einmal, da es genau einmal an die Liste L0 angehängt wird. Laufzeit: Da das erhöhen von c jeweils nur einen Schritt benötigt, bleibt die Laufzeit des Merge-Schritts O(n). (d) Wir verwenden den Mergesort Algorithmus und modifizieren den Merge-Schritt wie in (c) beschrieben. Daraus erhalten wir den Algorithmus M ERGE - AND -C OUNT, der für zwei sortierte Listen ( L` , Lr ) die Anzahl Inversionen c und die sortierte Liste L0 zurückgibt. Algorithm 1 S ORT- AND -C OUNT ( L) if | L| = 1 then return (0, L) end if if L > 1 then Teile die Liste in zwei Hälften L` and Lr mit | L` | = n2 und | Lr | = n2 (c` , L` ) = S ORT- AND -C OUNT ( L` ) (cr , Lr ) = S ORT- AND -C OUNT ( Lr ) (c, L0 ) = M ERGE - AND -C OUNT ( L` , Lr ) end if return (c + c` + cr , L0 ) Korrektheit: Da der Algorithmus M ERGE - AND -C OUNT gemäss (c) in jedem Merge-Schritt die Inversionen der sortierten Listen korrekt zählt, und man die Inversionen zählen kann indem man zuerst die Inversionen der beiden Hälften zählt, diese sortiert und dann die Inversionen der sortierten Liste addiert, folgt die Korrektheit. Laufzeit: Da M ERGE - AND -C OUNT in Zeit O(n) läuft folgt aus der Laufzeitanalyse von Mergesort, dass die Laufzeit von S ORT- AND -C OUNT O(n log n) ist. Lösungsvorschlag zu Aufgabe 3 Es bezeichne ZG REEDY und ZOPT den Wert der Greedy-Lösung bzw. der optimalen Lösung. Zu 2 zeigen ist, dass es für jedes (beliebig grosse) C ≥ 1 eine Instanz gibt, für die gilt ZOPT ZG REEDY ≥ C. Dazu seien ein Rucksack der Kapazität B ≥ 2C und Objekte I = {1, 2} mit p1 = 2, w1 = 1 und p2 = w2 = B gegeben. Dann liefert der Greedy-Algorithmus die Lösung IG REEDY = {1} mit ZG REEDY = 2. Die optimale Lösung dagegen ist IO PT = {2} mit ZO PT = B. Es gilt also B ZOPT = ≥ C. ZG REEDY 2 Der Greedy-Algorithmus kann also für das Rucksackproblem beliebig schlecht sein. Der Grund dafür ist, dass die gierige Strategie zu kurzsichtig ist und es möglich ist, dass dadurch später viel Platz im Rucksack ungenutzt bleibt. 3