Organisatorisches VL-21: Greedy Algorithmen • Vorlesung: Gerhard Woeginger (Zimmer 4024 im E1) Sprechstunde: Mittwoch 11:15–12:00 • Übungen: Tim Hartmann, David Korzeniewski, Björn Tauer Email: [email protected] (Datenstrukturen und Algorithmen, SS 2017) Gerhard Woeginger • Webseite: http://algo.rwth-aachen.de/Lehre/SS17/DSA.php • Nächste Vorlesung: Dienstag, Juli 18, Aula 1, zur gewohnten Zeit SS 2017, RWTH DSAL/SS 2017 VL-21: Greedy Algorithmen 1/39 DSAL/SS 2017 VL-21: Greedy Algorithmen 2/39 Greedy Algorithmen Grundlegendes • Grundlegendes optimal versus gut versus schlecht • Sequentielle Speicherung • Stundenplanung • Huffman Codes DSAL/SS 2017 VL-21: Greedy Algorithmen 3/39 DSAL/SS 2017 VL-21: Greedy Algorithmen 4/39 Greedy Algorithmen Greedy: kann optimal sein Greedy Algorithmen (greedy = gierig) I Trifft in jedem Schritt eine Entscheidung, die bezüglich eines “kurzsichtigen” Kriteriums optimal ist. I Dieses Kriterium ist einfach und schnell auszuwerten. I Wenn eine Wahl getroffen wurde, kann sie nicht mehr rückgängig gemacht werden. Wiederholung aus VL-16: Minimale Spannbäume Eingabe: ein gewichteter zusammenhängender Graph G mit n Knoten Ausgabe: ein minimaler Spannbaum von G Kruskal’s Algorithmus So lange weniger als n − 1 Kanten markiert sind: 1. Wähle eine billigste unmarkierte Kante I Greedy Algorithmen finden nicht immer die beste Lösung: Wiederholte Wahl eines lokalen Optimums führt nicht automatisch zum globalen Optimum I Greedy kann optimal sein (Beispiel folgt) I Greedy kann gut sein (Beispiel folgt) I Greedy kann beliebig schlecht sein (Beispiel folgt) DSAL/SS 2017 VL-21: Greedy Algorithmen 2. Markiere sie, falls sie keinen Kreis mit anderen markierten Kanten schliesst • Bei Terminierung bilden die markierten Kanten einen MST • n − 1 kurzsichtige, lokale Entscheidungen ergeben globales Optimum 5/39 Greedy: kann gut sein DSAL/SS 2017 VL-21: Greedy Algorithmen Greedy: kann beliebig schlecht sein (1) Knotenfärbungsproblem für Graphen Wiederholung aus VL-18: Matchings Eingabe: ein ungerichteter Graph G = (V , E ) Ausgabe: ein Matching mit maximaler Kardinalität Gegeben: ein ungerichteter Graph G = (V , E ) Ziel: Färbe die Knoten in V mit möglichst wenigen Farben, sodass benachbarte Knoten immer verschiedene Farben erhalten Greedy Algorithmus Offizielle Definition Wiederhole so lange es geht: Markiere neue Kante, die mit keiner markierten Kante kollidiert • Eine Färbung ist eine Funktion f : V → {1, . . . , k} sodass f (x ) 6= f (y ) für alle {x , y } ∈ E gilt. • Die chromatische Zahl χ(G) ist die kleinste Zahl k, für die eine derartige Färbung der Knoten existiert. • Bei Terminierung bilden die markierten Kanten ein Matching M • Kardinalität von Greedy Matching M ist mindestens 50% der Kardinalität des optimalen Matchings (Beweis: Jede Greedy Kante blockiert ≤ 2 optimale Kanten) DSAL/SS 2017 6/39 VL-21: Greedy Algorithmen • χ(Kn ) = n • Für jeden Baum T mit mindestens zwei Knoten gilt χ(T ) = 2 • Für n ≥ 1 gilt χ(C2n+1 ) = 3 7/39 DSAL/SS 2017 VL-21: Greedy Algorithmen 8/39 Greedy: kann beliebig schlecht sein (2) Greedy Algorithmus für Knotenfärbung So lange es einen ungefärbten Knoten gibt: 1. Wähle einen beliebigen Knoten v 2. Färbe Knoten v mit der kleinstmöglichen legalen Farbe Sequentielle Speicherung Beispiel Wir betrachten bipartiten Graphen mit • Knoten x1 , . . . xn und y1 , . . . yn • Kanten {xi , yj } ∈ E genau dann wenn i 6= j Falls Greedy die Reihenfolge x1 , y1 , x2 , y2 , x3 , y3 , . . . xn , yn verwendet, so braucht Greedy n verschiedene Farben Aber: χ(G) = 2 !! DSAL/SS 2017 VL-21: Greedy Algorithmen 9/39 Sequentielle Speicherung DSAL/SS 2017 VL-21: Greedy Algorithmen 10/39 Sequentielle Speicherung: Analyse Problem: Dateien am Magnetband Problem Eingabe: 1. Dateien D1 , . . . , Dn mit Längen L[1], . . . , L[n] 2. Ein Magnetband Ausgabe: Eine Anordnung der Dateien auf dem Magnetband, die die durchschnittliche Lesezeit minimiert. Eingabe: Zahlen L[1], . . . , L[n] Ausgabe: Permutation π, die n 1 X (n − k + 1) L[π(k)] minimiert n k=1 Angenommen, die Dateien sind in Reihenfolge D1 , . . . , Dn abgespeichert I Bei jedem Lesezugriff wird das Band vom Anfang an gelesen, bis korrekte Datei gefunden Pk Lesezeit für Dk ist dann i=1 L[i] Angenommen, an Stelle k liegt Datei mit Länge x und an Stelle k + 1 liegt Datei mit Länge y < x I Durchschnittliche Lesezeit beträgt dann • Beitrag zur Zielfunktion ist (n − k + 1)x + (n − k)y • Vertauschen der Dateien liefert neuen Beitrag (n − k + 1)y + (n − k)x • Neuer Beitrag ist besser/kleiner I n k 1 XX L[i] = n i=1 k=1 DSAL/SS 2017 n 1 X (n − k + 1) L[k] n k=1 VL-21: Greedy Algorithmen 11/39 DSAL/SS 2017 VL-21: Greedy Algorithmen 12/39 Sequentielle Speicherung: Lösung Variante mit Wahrscheinlichkeiten Problem Eingabe: Satz / Folgerung / Zusammenfassung Um die durchschnittliche Lesezeit zu minimieren, müssen Dateien nach monoton steigender Länge abgespeichert werden. 1. Dateien D1 , . . . , Dn 2. Längen L[1], . . . , L[n] der Dateien 3. Zugriffswahrscheinlichkeiten p[1], . . . , p[n] der Dateien (wobei Summe der p[i] gleich 1) Ausgabe: Eine Anordnung der Dateien auf dem Magnetband, die die erwartete Lesezeit minimiert. Greedy Algorithmus für Sequentielle Speicherung So lange noch (ungespeicherte) Dateien vorhanden sind: Angenommen, die Dateien sind in Reihenfolge D1 , . . . , Dn abgespeichert Pk I Lesezeit für Dk ist dann i=1 L[i] 1. Wähle eine kürzeste Datei 2. Speichere die Datei an der nächsten Stelle am Band ab I Durchschnittliche Lesezeit beträgt dann Resultierende Laufzeit ist O(n log n) n X k=1 DSAL/SS 2017 VL-21: Greedy Algorithmen 13/39 Variante mit Wahrscheinlichkeiten: Analyse Beitrag = (p + q) i=1 n X L[i] + (x + y ) k X i=1 L[i] = n X i=1 L[i] n X p[k] k=i VL-21: Greedy Algorithmen 14/39 Variante mit Wahrscheinlichkeiten: Lösung Angenommen, an Stelle k liegt Datei mit Länge x und Wahrscheinlichkeit p an Stelle k + 1 liegt Datei mit Länge y und Wahrscheinlichkeit q Angenommen, an Stelle k liegt Datei mit Länge x und Wahrscheinlichkeit p an Stelle k + 1 liegt Datei mit Länge y und Wahrscheinlichkeit q k−1 X DSAL/SS 2017 p[k] • alter Beitrag < neuer Beitrag genau dann wenn qx < py • alter Beitrag < neuer Beitrag genau dann wenn x /p < y /q p[j] + px + qy + qx j=k+2 Satz / Folgerung / Zusammenfassung Beitrag nach Vertauschen der beiden Dateien k−1 n X X = (p + q) L[i] + (x + y ) p[j] + px + qy + py i=1 Um die erwartete Lesezeit zu minimieren, müssen die Dateien nach monoton steigendem Quotienten L[i]/p[i] abgespeichert werden. j=k+2 • Wir erhalten einfachen Greedy Algorithmus • Kurze und populäre Dateien am Anfang des Bandes Lange und unpopuläre Dateien am Ende des Bandes • Resultierende Laufzeit ist O(n log n) Genaues Hingucken liefert: alter Beitrag < neuer Beitrag genau dann wenn qx < py DSAL/SS 2017 VL-21: Greedy Algorithmen 15/39 DSAL/SS 2017 VL-21: Greedy Algorithmen 16/39 Stundenplanung: Beispiel Stundenplanung DSAL/SS 2017 VL-21: Greedy Algorithmen 17/39 Stundenplanung: Beispiel DSAL/SS 2017 VL-21: Greedy Algorithmen 18/39 Stundenplanung: Problemstellung Problem: Stundenplanung Eingabe: 1. Vorträge V1 , . . . , Vn 2. Startzeiten L[1], . . . , L[n] der Vorträge 3. Endzeiten R[1], . . . , R[n] der Vorträge Ausgabe: Eine möglichst grosse Teilmenge von Vorträgen, die zeitlich nicht überlappen DSAL/SS 2017 VL-21: Greedy Algorithmen 19/39 DSAL/SS 2017 VL-21: Greedy Algorithmen 20/39 Stundenplanung: Beispiel, umgeordnet Greedy Algorithmus 1 2 3 4 5 6 7 8 9 10 11 12 DSAL/SS 2017 VL-21: Greedy Algorithmen 21/39 Korrektheit (1) Sortiere Vortraege nach ansteigendem Endpunkt R [ i ] // R [1] <= R [2] <= ... <= R [ n ] count = 1; Loesung [ count ] = 1; for ( i =2; i <= n ; i ++) { if ( L [ i ] > R [ count ]) { Loesung [++ count ] = i ; } } return Loesung [1.. count ]; DSAL/SS 2017 VL-21: Greedy Algorithmen 22/39 Korrektheit (2) Wir nehmen R[1] ≤ R[2] ≤ R[3] ≤ · · · ≤ R[n] an Satz Wir nehmen R[1] ≤ R[2] ≤ R[3] ≤ · · · ≤ R[n] an Es gibt eine optimale Lösung des Stundenplanung-Problems, die Vortrag V1 (mit kleinstem rechten Endpunkt R[1]) verwendet. Satz Beweis: • Betrachte beliebige optimale Lösung X ∗ , die V1 nicht verwendet • Betrachte Vortrag Vk in X ∗ mit kleinstem rechten Endpunkt R[k] • Dann gilt R[k] ≥ R[1] • Wir können problemlos in X ∗ den Vortrag Vk durch V1 ersetzen • Neue zulässige Lösung mit gleich vielen Vorträgen wie X ∗ • Ergo: neue Lösung ebenfalls optimal Beweis: • Wir betrachten optimale Lösung X ∗ , die V1 enthält • Dann enthält X ∗ keinen Vortrag, der mit V1 überlappt • Wir löschen V1 und alle überlappenden Vorträge • Wir argumentieren induktiv für die weiteren Vorträge DSAL/SS 2017 VL-21: Greedy Algorithmen Der Greedy Algorithmus berechnet eine optimale Lösung. 23/39 DSAL/SS 2017 VL-21: Greedy Algorithmen 24/39 Anmerkung zu Greedy Algorithmen Die Korrektheitsargumente • für den Greedy Algorithmus zur sequentiellen Speicherung und • für den Greedy Algorithmus zur Stundenplanung sind ganz ähnlich strukturiert. Intermezzo: Anmerkung zu Greedy Algorithmen I Angenommen, es gibt eine optimale Lösung, die sich von der Greedy Lösung unterscheidet I Finde den “ersten” Unterschied zwischen den beiden Lösungen I Argumentiere, dass man die optimale Entscheidung durch die Greedy Entscheidung ersetzen kann, ohne die Qualität zu verschlechtern • Sequentielle Speicherung: kleinster Index mit L[π(k)] > L[π(k + 1)] • Stundenplanung: frühester Vortrag mit (lokal) nicht-kleinstem rechten Endpunkt DSAL/SS 2017 VL-21: Greedy Algorithmen 25/39 DSAL/SS 2017 VL-21: Greedy Algorithmen 26/39 Definitionen (1) I Ein Binär-Code kodiert jeden Buchstaben eines Alphabets Σ durch einen String von 0en und 1en I Ein Binär-Code ist präfix-frei, wenn kein Codewort der Präfix eines anderen Codeworts ist. Huffman Codes Beispiel DSAL/SS 2017 VL-21: Greedy Algorithmen 27/39 I 7-Bit ASCII kodiert jeden Buchstaben durch einen String mit 7 Bits. 7-Bit ASCII ist ein präfix-freier Binär-Code. I Der Morse-Code ist ein Binär-Code. Der Morse-Code ist nicht präfix-frei: Codewort für A (· –) ist Präfix des Codeworts für J (· – – –) DSAL/SS 2017 VL-21: Greedy Algorithmen 28/39 Definitionen (2) Definitionen (3) Jeder präfix-freie Binär-Code kann durch Binär-Baum dargestellt werden: I Die Buchstaben des Alphabets Σ sind in den Blättern I Das Codewort für Buchstaben entspricht Pfad von Wurzel zu Blatt Optimierungsziel: Kodierte Botschaften sollen so kurz wie möglich sein I Entlang des Pfades gilt: Links=0 und Rechts=1 Problem: Optimaler präfix-freier Binär-Code I Länge des Codeworts = Tiefe des Blattes im Baum Eingabe: 1. Ein Alphabet Σ mit n Buchstaben 2. Die Texthäufigkeiten h1 , h2 , . . . , hn der Buchstaben Ausgabe: Ein präfix-freier Binär-Code, der die Gesamtlänge der kodierten Botschaft minimiert: k X Gesamtlänge = hi · Tiefe[i] i=1 DSAL/SS 2017 VL-21: Greedy Algorithmen 29/39 Beispiel (1) DSAL/SS 2017 VL-21: Greedy Algorithmen 30/39 Beispiel (2) 170 59 A 3 O 9 C 3 R 6 D 2 S 27 E 26 T 22 F 5 U 2 G 3 V 5 H 8 W 8 I 13 X 4 L 2 Y 5 S 27 N 16 Z 1 111 32 60 N 16 16 H 8 W 8 39 O 9 8 VL-21: Greedy Algorithmen 31/39 DSAL/SS 2017 10 F 5 11 V 5 E 26 25 Y 5 U 2 I 13 12 R 6 6 A 3 4 L 2 DSAL/SS 2017 21 T 22 17 X 4 51 6 C 3 G 3 3 D 2 VL-21: Greedy Algorithmen Z 1 32/39 Huffman Algorithmus Huffman Algorithmus Build-Huffman-Tree 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 David Albert Huffman (1925–1999): Amerikanischer Computer Scientist; MIT; UC Santa Cruz Greedy Algorithmus (Huffman, 1951) So lange zwei oder mehr Buchstaben vorhanden sind: 1. Verschmilz die beiden Buchstaben mit kleinster Häufigkeit h und h0 2. Das verschmolzene Resultat erhält Häufigkeit h + h0 Implementierung: mit MinHeap (ExtractMin; Insert) DSAL/SS 2017 VL-21: Greedy Algorithmen 33/39 Korrektheit (1) void HuffmanTree ( int & frequency [2 n ] , & L [2 n ] , & R [2 n ] , & parent [2 n ]) { for ( i =1; i <= n ; i ++) { L [ i ]=0; R [ i ]=0; insert (i , frequency [ i ]) } for ( i = n +1; i <=2 n -1; i ++) { x = ExtractMin () ; y = ExtractMin () ; frequency [ i ] = frequency [ x ]+ frequency [ y ] L [ i ]= x ; R [ i ]= y ; parent [ x ]= i ; parent [ y ]= i ; Insert (i , frequency [ i ]) } parent [2 n -1]= 0; } DSAL/SS 2017 VL-21: Greedy Algorithmen 34/39 Korrektheit (2) Unser Ziel: Wir wollen nun zeigen, dass der Huffman Algorithmus für jede Folge h1 , . . . , hn von Häufigkeiten einen optimalen präfix-freien Binär-Code berechnet. Beobachtung Es seien a mit Häufigkeit ha und b mit Häufigkeit hb zwei Buchstaben mit geringster Häufigkeit. Dann existiert ein optimaler präfix-freier Binär-Code, in dessen Baum die beiden Buchstaben a und b Die Fälle n ≤ 2 sind trivial. Wir nehmen von jetzt an n ≥ 3 an. 1. Geschwister sind, und 2. zwei Blätter mit maximaler Tiefe sind. Beobachtung Beweis: • Andernfalls vertauschen wir Blatt a mit Blatt x mit maximaler Tiefe • Tiefe[a] = alte Tiefe von a; Tiefe[x ] = alte Tiefe von x • Man rechnet leicht nach: ha · Tiefe[a] + hx · Tiefe[x ] ≥ ha · Tiefe[x ] + hx · Tiefe[a] Wir betrachten einen optimalen präfix-freien Binär-Code. Es sei b ein Blatt mit maximaler Tiefe im entsprechenden Binär-Baum. Dann gibt es ein anderes Blatt b 0 , das die selbe Tiefe und den selben Vater wie b hat. DSAL/SS 2017 VL-21: Greedy Algorithmen 35/39 DSAL/SS 2017 VL-21: Greedy Algorithmen 36/39 Korrektheit (3) Korrektheit (4) • Wir betrachten Häufigkeiten H = (h1 , . . . , hn ) mit h1 ≥ h2 ≥ · · · ≥ hn • Es sei T der optimale Baum für H • OBdA: Die beiden Buchstaben mit Häufigkeiten hn−1 und hn sind Blätter in T , mit maximaler Tiefe und mit selbem Vater I cost(T ) cost(T ) = = cost(T 0 ) + (hn−1 + hn ) folgt, dass wir nur die Kosten von T 0 minimieren müssen, falls wir die Kosten von T minimieren wollen • Wir konstruieren neuen Baum T 0 : Wir verschmelzen diese beiden Blätter mit Vater, und geben Vater v 0 die Häufigkeit h0 := hn−1 + hn • Tiefe[v 0 ] = Tiefe[n] − 1 k X Aus der Gleichung I Restproblem: Finde einen optimalen präfix-freien Binär-Code für die Häufigkeiten H 0 = (h1 , h2 , . . . , hn−2 , hn−1 + hn ) I Induktives Argument: Huffman liefert optimalen Binär-Baum für H 0 Ergo: Huffman liefert optimalen Binär-Baum für H hi · Tiefe[i] i=1 Satz = cost(T 0 ) + hn−1 · Tiefe[n] + hn · Tiefe[n] − h0 · Tiefe[v 0 ] Der Huffman Algorithmus bestimmt für jede Häufigkeits-Verteilung einen optimalen präfix-freien Binär-Code. = cost(T 0 ) + (hn−1 + hn − h0 ) · Tiefe[n] + h0 = cost(T 0 ) + (hn−1 + hn ) DSAL/SS 2017 VL-21: Greedy Algorithmen 37/39 Organisatorisches • Nächste Vorlesung: Dienstag, Juli 18, Aula 1, zur gewohnten Zeit • Webseite: http://algo.rwth-aachen.de/Lehre/SS17/DSA.php DSAL/SS 2017 VL-21: Greedy Algorithmen 39/39 DSAL/SS 2017 VL-21: Greedy Algorithmen 38/39