Programmieren, Algorithmen und Datenstrukturen II 8. Allgemeine Lösungsverfahren



Ähnliche Dokumente
Einstieg in die Informatik mit Java

Algorithmen und Datenstrukturen (für ET/IT)

Algorithmen und Datenstrukturen (für ET/IT)

1 Einführung. 2 Grundlagen von Algorithmen. 3 Grundlagen von Datenstrukturen. 4 Grundlagen der Korrektheit von Algorithmen

Dynamisches Programmieren - Problemstruktur

Dynamische Programmierung II

Das Problem des Handlungsreisenden

Theoretische Informatik. Exkurs: Komplexität von Optimierungsproblemen. Optimierungsprobleme. Optimierungsprobleme. Exkurs Optimierungsprobleme

Übungen zum Vortrag Backtracking mit Heuristiken

Lösungen von Übungsblatt 12

Grundlagen der Algorithmen und Datenstrukturen Kapitel 12

Backtracking mit Heuristiken

ADS: Algorithmen und Datenstrukturen 2

II.3.1 Rekursive Algorithmen - 1 -

Was der Mathematiker Gauß nicht konnte, das können wir Prof. R. Zavodnik/C++ Vorlesung/Kapitel IX 1

Stack. Seniorenseminar Michael Pohlig

Uninformierte Suche in Java Informierte Suchverfahren

Algorithmen und Datenstrukturen 2. Stefan Florian Palkovits, BSc Juni 2016

Algorithmen und Datenstrukturen 2 VU 3.0 Nachtragstest SS Oktober 2016

Sortierverfahren. Sortierverfahren für eindimensionale Arrays

Algorithmen und Datenstrukturen 1 Kapitel 3

11.1 Grundlagen - Denitionen

13 Java 4 - Entwurfsmuster am Beispiel des Rucksackproblems

Übungen zur Vorlesung Datenstrukturen und Algorithmen SS 07 Beispiellösung Blatt 5

Algorithmen und Datenstrukturen 2

Stud.-Nummer: Datenstrukturen & Algorithmen Seite 1

Wiederholung. Divide & Conquer Strategie

Datenstrukturen & Algorithmen

Algorithmen und Datenstrukturen 2

Algorithmen und Datenstrukturen

Der Dreyfus-Wagner Algorithmus für das Steiner Baum Problem

Algorithmen und Datenstrukturen 2

Fallstudie: Online-Statistik

Datenstrukturen Teil 2. Bäume. Definition. Definition. Definition. Bäume sind verallgemeinerte Listen. Sie sind weiter spezielle Graphen

21. Greedy Algorithmen. Aktivitätenauswahl, Fractional Knapsack Problem, Huffman Coding Cormen et al, Kap. 16.1, 16.3

Rückblick: divide and conquer

Einführung in die Objektorientierte Programmierung Vorlesung 17: Dynamische Programmierung. Sebastian Küpper

Klausur Algorithmentheorie

Kapitel 2. Weitere Beispiele Effizienter Algorithmen

Uninformierte Suche in Java Informierte Suchverfahren

7. Transitive Hülle. Kante des Graphen. Zusatz-Kante der transitiven Hülle

Datenstrukturen und Algorithmen D-INFK

ADS: Algorithmen und Datenstrukturen 2

Große Lösungsräume. Leon Schmidtchen Hallo Welt Seminar - LS Leon Schmidtchen Große Lösungsräume Hallo Welt Seminar - LS2

Algorithmen und Datenstrukturen 2. Stefan Florian Palkovits, BSc Juni 2016

Lösungsvorschlag Serie 2 Rekursion

Der Branching-Operator B

Pro Informatik 2009: Objektorientierte Programmierung Tag 18. Marco Block-Berlitz, Miao Wang Freie Universität Berlin, Institut für Informatik

Algorithmen & Datenstrukturen Midterm Test 2

Algorithmen und Komplexität Lösungsvorschlag zu Übungsblatt 8

TECHNISCHE UNIVERSITÄT MÜNCHEN FAKULTÄT FÜR INFORMATIK

3.2. Divide-and-Conquer-Methoden

public static void main(string[] args) {

Übung Algorithmen und Datenstrukturen

Einführung in Heuristische Suche

Informatik II Übung 8 Gruppe 4

Informatik II Übung 09

Datenstrukturen und Algorithmen. Christian Sohler FG Algorithmen & Komplexität

Kapitel 9: Lineare Programmierung Gliederung

Algorithmische Bioinformatik 1

QuickSort ist ein Sortieralgorithmus, der auf der Idee des Teile & Beherrsche beruht, und das gegebene Array an Ort und Stelle (in place) sortiert

6.1. Ein Approximationsalgorithmus für das Rucksackproblem

f 1 (n) = log(n) + n 2 n 5 f 2 (n) = n 3 + n 2 f 3 (n) = log(n 2 ) f 4 (n) = n n f 5 (n) = (log(n)) 2

Übung zu Algorithmen und Datenstrukturen (für ET/IT)

Algorithmen und Datenstrukturen 2

Martin Unold INFORMATIK. Geoinformatik und Vermessung

Algorithmen und Datenstrukturen (Th. Ottmann und P. Widmayer) Folien: Suchverfahren Autor: Stefan Edelkamp / Sven Schuierer

NP-vollständige Probleme

Kapitel 10. Komplexität von Algorithmen und Sortieralgorithmen

3. Übungsblatt zu Algorithmen I im SoSe 2017

Algorithmen und Datenstrukturen (für ET/IT)

Weitere Algorithmenentwurfstechniken

2.2 Der Algorithmus von Knuth, Morris und Pratt

Übung Algorithmen und Datenstrukturen

Hallo Welt für Fortgeschrittene

Effiziente Algorithmen 2

12. Rekursion Grundlagen der Programmierung 1 (Java)

Kapitel 5: Dynamisches Programmieren Gliederung

Informatik II, SS 2014

Algorithmen und Datenstrukturen

15. Algorithmus der Woche Das Rucksackproblem Die Qual der Wahl bei zu vielen Möglichkeiten

Gliederung. 5. Compiler. 6. Sortieren und Suchen. 7. Graphen

Elementare Sortierverfahren

Computational Intelligence

Counting - Sort [ [ ] [ [ ] 1. SS 2008 Datenstrukturen und Algorithmen Sortieren in linearer Zeit

Datenstrukturen und Algorithmen (SS 2013)

Verschlüsseln eines Bildes. Visuelle Kryptographie. Verschlüsseln eines Bildes. Verschlüsseln eines Bildes

Algorithmische Geometrie: Delaunay Triangulierung (Teil 2)

Stud.-Nummer: Datenstrukturen & Algorithmen Seite 1

Ansätze zur Erfassung von Faktoren durch Prüfungsaufgaben. (Diskussionen in Dagstuhl sowie mit Prof. Nickolaus, Technikpädagogik, U Stuttgart)

Lernmodul 7 Algorithmus von Dijkstra

Kapitel 5: Paradigmen des Algorithmenentwurfs. Gliederung

Übung Algorithmen und Datenstrukturen

Datenstrukturen sind neben Algorithmen weitere wichtige Bausteine in der Informatik

Interne Sortierverfahren

Programmieren 1 C Überblick

Transkript:

Programmieren, Algorithmen und Datenstrukturen II 8. Allgemeine Lösungsverfahren 1

Übersicht 1. Ziele des Kapitels 2. Bereits behandelte Lösungsstrategien 3. Backtracking 4. Branch-and-Bound 5. Weiterführende Lösungsstrategien 2

1. Ziele des Kapitels Kapitel C++ und SW Engineering Algorithmen und Datenstrukturen 1 2 Ein- / Ausgabe mit Dateien, Ausnahmebehandlung Vererbung 4 3 Abstrakte Datentypen + Klassen-Templates Überladen von Operatoren 5 Sortieren und Suchen 6 Bäume 7 Graphen 8 Allgemeine Lösungsverfahren 3

1. Ziele des Kapitels Dieses Kapitel richtet sich besonders an die Lösung von Problemen, für die (noch) kein (offensichtlicher) Algorithmus existiert. Hierfür werden Standard- Verfahren wie Backtracking oder Branch-and-Bound heran gezogen, die einem allgemeinen Schema folgen und somit universell einsetzbar sind. Hiermit ist es möglich je nach Problemstellung irgendeine, alle oder die optimale Lösung zu finden. In diesem Zusammenhang kommen weitere algorithmische Standard-Problem (z.b. das Rucksack-Problem) zur Sprache. 4

2. Bereits behandelte Lösungsstrategien 2.1 Divide-and-Conquer Divide-and-Conquer (D&C) ist in dieser Veranstaltung bereits des öfteren vorgestellt und angewendet worden: Ein Problem wird solange (rekursiv) zerlegt, bis man bei einer einfach zu lösenden atomaren Größe angelangt ist. Danach werden die Einzellösungen zu jeweils größeren kombiniert. Vor- und Nachteile: D&C-Ansätze sind immer sehr speziell an einem Problem orientiert, d.h. es gibt keine allgemeine Standard-Vorgehensweise. Sehr gute Resultate werden erzielt z.b. beim MergeSort und Quicksort Schlechte hingegen z.b. bei der Berechnung der Fibonacci-Zahlen 5

2. Bereits behandelte Lösungsstrategien 2.2 Dynamische Programmierung Dynamische Programmierung (DP) bedeutet: Zuerst die Lösungen der kleinsten Teilprobleme direkt zu berechnen, und diese dann geeignet zu einer Lösung eines nächstgrößeren Teilproblems zusammenzusetzen. Einmal berechnete Teilergebnisse werden in einer Tabelle gespeichert, so dass nachfolgende Berechnungen gleichartiger Teilprobleme auf diese zurückgreifen können (anstatt sie jedes Mal neu zu berechnen). Vor- und Nachteile: Im Vergleich zu D&C, vermeidet DP kostspielige Rekursionen, weil bekannte Teilergebnisse wiederverwendet werden. DP-Ansätze sind immer sehr speziell an einem Problem orientiert und bedürfen einer fundierten mathematischen Grundlage. Fehlt diese oder ändert sich die Problemstellung auch nur geringfügig ist DP nicht anwendbar. Mit DP lassen sich sehr effiziente Lösungen erzielen (z.b. Fibonacci- Zahlen, Kürzeste Wege) 6

3. Backtracking In der allgemeinen Problemlösung geht es darum, einen Algorithmus zum Finden von Lösungen einer Gruppe von Problemen zu bestimmen und zwar nicht durch Befolgen einer direkten Vorschrift für die Berechnung, sondern durch Ausprobieren (trial and error). Solche Algorithmen sind erst seit dem Beginn des Computer-Zeitalters von Bedeutung. Wir betrachten: das Finden (irgend) einer Lösung das Finden aller Lösungen das Finden der/einer optimalen Lösung 7

3. Backtracking 3.1 Das Damen Problem Dies wird dargestellt mit Hilfe eines algorithmischen Klassikers: Es sollen jeweils acht Damen auf einem Schachbrett so aufgestellt werden, dass keine zwei Damen einander nach den Schachregeln schlagen können. Oder anders ausgedrückt: Es sollen sich keine zwei Damen die gleiche Reihe, Linie oder Diagonale teilen. Das Problem kann auf Schachbretter beliebiger Größe verallgemeinert werden. Dann gilt es, n Damen auf einem Brett von n x n Feldern zu positionieren. Für n=8 hat das Damenproblem 92 verschiedene Lösungen. Betrachtet man Lösungen als gleich, die sich durch Spiegelung oder Drehung des Brettes aus einander ergeben, verbleiben noch zwölf Lösungen. 8

3. Backtracking 3.2 Irgendeine Lösung finden Oft ist man nur am Finden einer einzelnen Lösung interessiert, auch wenn es eigentlich mehrere gibt. Das Backtracking-Verfahren ist eine allgemeine Lösungsmethode dafür. Es funktioniert so, wie man sich den Ausweg aus einem Labyrinth vorstellen kann: Man geht solange in eine bestimmte Richtung, bis es nicht mehr weiter geht. Dann geht man zurück an eine Stelle, wo man bereits war und versucht es von dort aus in einen andere Richtung. Das Ziel eines Backtracking-Verfahrens ist es, n Schritte erfolgreich zu absolvieren, wobei es in jedem Schritte mehrere Alternativen geben kann, die erkunden werden müssen. Dies entspricht einer vollständigen Suche: wenn alle Alternativen in allen n Schritten untersucht worden sind, gibt es keine Lösung. Man beachte dabei, dass die gewählten Alternativen in vorherigen Schritten die der nachfolgenden beeinflussen. 9

3. Backtracking Man erhält folgenden Algorithmus in Form einer Funktion: VersucheDieNächstenSchritte( i i )) DO DO Wähle Wähle die die nächste nächste Alternative Alternative k k für für Schritt Schritt ii IF IF annehmbar annehmbar (i, (i, k) k) Zeichne Zeichne (i,k) (i,k) auf auf IF IF (i+1 (i+1 < n) n) // // d.h. d.h. Lösung Lösung noch noch unvollständig VersucheDieNächstenSchritte( i+1 i+1 )) IF IF NICHT NICHT erfolgreich erfolgreich Lösche Lösche die die Aufzeichnung (i,k) (i,k) WHILE WHILE (NICHT (NICHT erfolgreich erfolgreich UND UND NICHT NICHT alle alle Alternativen Alternativen untersucht) untersucht) Aufruf: VersucheDieNächstenSchritte( 0 ) 10

3. Backtracking Für das Damenproblem erhält man folgendes C++-Programm: bool TryNextSteps(int i) { // versuche Dame 'i' und folgende zu platzieren coord pos = nullpkt; // wähle erste Position bool success = false; do { if (acceptable(pos)) { set(i, pos); success = true; if (i + 1 < n) { // mache die nächsten Schritte (alle weiteren Damen): success = TryNextSteps(i + 1); // In Sackgasse gelaufen: mache letzten Schritt rückgängig if (!success) remove(pos); if (!success &&!pos.end()) // versuche es im nächsten Feld pos.next(); while (!success &&!pos.end()); return success; 11

3. Backtracking Das Schachbrett ist dabei ein zweidimensionales Array: class coord { public: coord(int px = 0, int py = 0) : x(px), y(py) { ; // Get-Methoden int X() { return x; ; int Y() { return y; ; void next() { // ein Feld weiter rücken x++; ; if (x == n) { x = 0; y++; bool end() { // letztes Feld erreicht return x == n - 1 && y == n - 1; ; bool valid() { // Koordinate liegt im Feld if (x < 0 x >= n) return false; if (y < 0 y >= n) return false; return true; private: int x; int y; ; const coord nullpkt(0, 0); int Field[n][n]; 12

3. Backtracking Mit den folgenden Hilfsfunktionen ist das Programm (fast) komplett: bool acceptable(coord pos) { // prüfe, ob weitere Dame an Position 'pos' stehen kann for (int i = 0; i < n; i++) { // Horizontale: if (Field[i][pos.Y()]!= FREE) return false; // Vertikale: if (Field[pos.X()][i]!= FREE) return false; // Diagonalen:... return true; void set(int i, coord pos) { // setze Dame 'i' an Position 'pos' Field[pos.X()][pos.Y()] = i; void remove(coord pos) { // entferne Dame von Position 'pos' Field[pos.X()][pos.Y()] = FREE; 13

3. Backtracking Bemerkung: Die Laufzeit des vorgestellten Algorithmus hängt davon ab, wie schnell eine gültige Lösung gefunden wird. Je nach Problemstellung kann dabei die Reihenfolge, in der die einzelnen Alternativen angeboten werden, die Laufzeit erheblich beeinflussen. Bei symmetrischen Problemen (wie im Beispiel der acht Damen) kann die Laufzeit reduziert werden, indem bei einem neuen Schritt nicht noch einmal dieselben Alternativen untersucht werden wie bei den vorhergehenden Schritten. Frage: Wie genau muss dafür das Programm von eben verändert werden? 14

3. Backtracking 3.3 Alle Lösungen finden Um alle Lösungen finden zu können, muss der Backtracking-Algorithmus nur geringfügig verändert werden (es wird eine vollständige Suche durchgeführt): VersucheDieNächstenSchritte( i i )) FORALL: FORALL: Wähle Wähle die die nächste nächste Alternative Alternative k k (von (von m) m) für für Schritt Schritt ii IF IF annehmbar annehmbar (i, (i, k) k) Zeichne Zeichne (i,k) (i,k) auf auf IF IF (i+1 (i+1 < n) n) // // d.h. d.h. Lösung Lösung noch noch unvollständig VersucheDieNächstenSchritte( i+1 i+1 )) ELSE ELSE Drucke Drucke Lösung Lösung Lösche Lösche die die Aufzeichnung (i,k) (i,k) Frage: Aufwand? 15

4. Branch-and-Bound 4.1 Vollständige Suche mit Bewertung Will man die optimale Lösung finden, muss eine Bewertungsfunktion f() bestimmen, was eine gute von einer schlechten Lösung unterscheidet, so dass unterschiedliche Lösungen einfach verglichen werden können. Damit kann die vollständige Suche von eben, wie folgt verändert werden: VersucheDieNächstenSchritte( i i )) FORALL: FORALL: Wähle Wähle die die nächste nächste Alternative Alternative k k (von (von m) m) für für Schritt Schritt ii IF IF annehmbar annehmbar (i, (i, k) k) Zeichne Zeichne (i,k) (i,k) auf auf IF IF (i+1 (i+1 < n) n) // // d.h. d.h. Lösung Lösung noch noch unvollständig VersucheDieNächstenSchritte( i+1 i+1 )) ELSE ELSE IF IF f(lösung) f(lösung) < f(minimum) f(minimum) Minimum Minimum := := Lösung Lösung Lösche Lösche die die Aufzeichnung (i,k) (i,k) 16

4. Branch-and-Bound Der offensichtliche Nachteil dieses Verfahrens ist, dass immer eine vollständige Suche durchgeführt wird. Außerdem passt dieses Lösungsschema nicht so richtig zu vielen Optimierungsproblemen besonders zu solchen die eine Auswahl treffen sollen, ob ein bestimmtes Element in die Lösung aufgenommen werden soll oder nicht. 4.2. Branch-and-Bound Schema Daher wird i.f. ein weiteres Lösungsschema vorgestellt, dass speziell für Optimierungsprobleme gedacht ist. Ein Branch-and-Bound-Algorithmus ist ein Verfahren, das insbesondere versucht, nicht den kompletten Suchraum erkunden zu müssen: Sobald klar, dass sich an einer bestimmten Stelle die Fortsetzung nicht mehr lohnt, bricht das Verfahren ab, und macht ggf. woanders weiter. 17

4. Branch-and-Bound Oft geht es bei Optimierungsproblemen um eine Auswahl aus n Objekten. Ein Algorithmus muss also für jedes Objekt entscheiden, ob es teil der Lösung sein kann (Einschlusskriterium) oder ob es nicht teil der Lösung sein kann (Ausschlusskriterium) VersucheDieNächstenObjekte( i i )) IF IF Einschluss Einschluss von von (i) (i) möglich möglich Zeichne Zeichne (i) (i) auf auf IF IF (( i+1 i+1 < n n ))//// d.h. d.h. Lösung Lösung noch noch unvollständig unvollständig VersucheDieNächstenObjekte( i+1 i+1 )) ELSE ELSE Prüfe Prüfe Optimalität Optimalität Lösche Lösche die die Aufzeichnung Aufzeichnung (i) (i) IF IF Ausschluss Ausschluss von von (i) (i) möglich möglich IF IF (( i+1 i+1 < n n ))//// d.h. d.h. Lösung Lösung noch noch unvollständig unvollständig VersucheDieNächstenObjekte( i+1 i+1 )) ELSE ELSE Prüfe Prüfe Optimalität Optimalität 18

4. Branch-and-Bound 4.3 Das Rucksack-Problem Dies wird dargestellt mit Hilfe eines algorithmischen Klassikers, dem Rucksack- Problem: Aus einer Menge von Objekten, die jeweils ein Gewicht und einen Nutzwert haben, soll eine Teilmenge ausgewählt werden, deren Gesamtgewicht eine vorgegebene Gewichtsschranke nicht überschreitet. Unter dieser Bedingung soll der Nutzwert der ausgewählten Objekte maximiert werden. Das Einschlusskriterium ist dabei, das zulässige Gesamtgewicht nicht zu überschreiten, wenn ein Objekt dazu kommt. Das Ausschlusskriterium besteht daraus zu prüfen, ob noch ein neuer Optimal-Wert zu erzielen ist, wenn ein Objekt weggelassen wird. 19

4. Branch-and-Bound Lösung in C++: void TryNextObjects(int i, int Weight, int ReachableValue) { if (Weight + A[i].GetWeight() <= MaxWeight ) { // Einschluss-Kriterium pack(i); // Zeichne (i) auf if ( i+1 < n ) // d.h. Lösung noch unvollständig TryNextObjects( i+1, Weight + A[i].GetWeight(), ReachableValue ); else SetMax(); // Prüfe Optimalität unpack(i); // Lösche die Aufzeichnung (i) if (ReachableValue - A[i].GetValue() > MaxValue ) { // Ausschluss-Kriterium if ( i+1 < n ) // d.h. Lösung noch unvollständig TryNextObjects( i+1, Weight, ReachableValue - A[i].GetValue() ); else SetMax(); // Prüfe Optimalität 20

4. Branch-and-Bound Die Daten werden wie folgt verwaltet: const int n = 10; const int MaxWeight = 110; int TotalValue; int MaxValue; item A[n]; bool Knapsack[n]; bool OptKnapsack[n]; // Anzahl Elemente // Maximales Gewicht des Rucksacks // gesamt möglicher Maximalwert // aktueller Maximalwert // Elemente // aktueller Rucksack // optimaler Rucksack void init() { // alles initialisieren int W[n] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ; int V[n] = {18, 20, 17, 19, 25, 21, 27, 23, 25, 24 ; TotalValue = 0; for (int i=0; i < n; i++) { A[i] = item(v[i], W[i]); TotalValue += V[i]; Knapsack[i] = false; OptKnapsack[i] = false; MaxValue = 0; 21

4. Branch-and-Bound Mit den folgenden Hilfsfunktionen ist das Programm (fast) komplett: void pack(int i) { Knapsack[i] = true; // aufzeichnen void unpack(int i) { // Aufzeichnung löschen Knapsack[i] = false; void SetMax() { int Value = 0; // Optimalität prüfen // Wert des aktuellen Rucksacks for (int i=0; i < n; i++) if (Knapsack[i]) Value += A[i].GetValue(); if (Value > MaxValue) { // neues Maximum gefunden MaxValue = Value; for (int i=0; i < n; i++) OptKnapsack[i] = Knapsack[i]; 22

5. Weiterführende Lösungsstrategien Manchmal ist ein Problem so veranlagt (NP-hart), dass auch mit Branch-and- Bound oder Dynamischer Programmierung keine Lösung in annehmbarer Zeit gefunden werden kann. Dann kommt nur eine Heuristik in Frage also ein Algorithmus der versucht, eine einigermaßen gute Lösung (d.h. eine Näherungslösung) in passabler Zeit zu finden. Dafür existieren folgende Lösungsansätze: Greedy (gierig) Strategien wählen immer ausgehend vom momentanen Standpunkt als nächstes die erfolgversprechendste Alternative. Ohne Backtracking ist ein solcher Ansatz i.d.r. sehr schnell (~ O(n)). Einfache Heuristiken sind problembezogene Standard-Verfahren (z.b. beim Scheduling oder bei der Verschnitt-Optimierung), die einer festen Vorschrift folgen (z.b. Shortest-Job-First) und damit ebenfalls sehr schnell fertig sind. Allgemeine Optimierer (z.b. Simulated Annealing, Genetische Algorithmen) sind Verfahren, die sich mehr Zeit nehmen und vorhandene Lösungen modifizieren und dann gegeneinander abwägen (z.b. Stundenplanung) 23