Sie sind auf Seite 1von 4

Algorithmen und Datenstrukturen FAU, Informatik 2, AUD-Team

Wintersemester 2018/19 aud@i2.cs.fau.de

4. Übung
Abgabe bis 19.11.2018, 10:00 Uhr

Einzelaufgabe 4.1: Induktionsbeweis 14 EP


Gegeben sei folgende Java-Methode:
1 p u b l i c s t a t i c l o n g magic ( l o n g n ) {
2 i f ( n > 2) {
3 r e t u r n 9 * magic ( n − 2 ) − 1 6 ;
4 } else {
5 return 2 * n + 1;
6 }
7 }

a) Beweisen Sie folgenden Zusammenhang formal mittels vollständiger Induktion:


n−2
X
∀n ≥ 1 : magic(n) = 3n − 4 · 3i = 3n − 4 · 30 + 31 + 32 + . . . + 3n−3 + 3n−2

i=0

Zur Vereinfachung nehmen Sie bitte an, dass der Wertebereich des Rückgabetyps long un-
beschränkt ist, dass also kein Überlauf auftreten kann. Bitte strukturieren Sie Ihren Beweis
so, dass er leicht nachvollziehbar ist – geben Sie insbesondere alle Induktionsanfänge bzw.
Induktionsvoraussetzungen explizit an.
b) Beweisen Sie, dass die Methode immer terminiert. Geben Sie dazu eine Terminierungsfunk-
tion an und begründen Sie kurz Ihre Wahl.
Geben Sie Ihre Lösung als Induktionsbeweis.pdf über EST ab.

Einzelaufgabe 4.2: Guten Stoff optimal verkaufen 11 EP


Stellen Sie sich vor, Sie handeln mit seltenem und teurem Stoff. Angenommen zum Beispiel, Sie
möchten eine Bahn mit 8m Länge verkaufen. Am Stück bringt Ihnen das 20 e ein, aber wenn Sie
den Stoff in kleinere Abschnitte zerteilen und gemäß folgender Preistabelle verkaufen, dann können
Sie sogar 22 e (1 × 2m und 1 × 6m) verdienen:
Länge 1 2 3 4 5 6 7 8 ...
Preis 1 5 8 9 10 17 17 20 . . .
Würde das 1m-Stück 3 e statt nur 1 e kosten, dann würde es sich sogar lohnen, die 8m in Einzel-
teilen zu 1m zu verkaufen – was den Erlös auf 24 e klettern lässt.
Gegeben ein Ballen der Länge int stoff und eine Liste long[] preise mit den Preisen für
Stücke der Länge ¬ bis inklusive preise.length (!): Welches ist der maximal mögliche Gewinn?
Implementieren Sie in einer Klasse StoffVerkaufen exakt die folgenden beiden öffentlichen sta-
tischen Methoden (jedoch keine weiteren Methoden oder Attribute!):
a) long verkaufenNaive(Polizei p, int stoff, long[] preise) soll den höchst-
möglichen Gewinn rekursiv und ohne weitere Optimierung berechnen und zurückgeben.
b) long verkaufenDP(Polizei p, int stoff, long[] preise) soll diese Aufgabe
nunmehr iterativ mittels dynamischer Programmierung lösen, indem sie ein methodenlokales
memoization-Feld geeignet (Bottom-Up) befüllt.

-1-
Algorithmen und Datenstrukturen FAU, Informatik 2, AUD-Team
Wintersemester 2018/19 aud@i2.cs.fau.de

ACHTUNG – WICHTIG:
I Rufen Sie gleich zu Beginn JEDER Ihrer Methoden unbedingt einmal p.kontrolle() auf.
Dieser Aufruf dient der automatischen Überprüfung/Bewertung Ihrer Implementierung!
I Betrachten Sie nur die Eingabe stoff ≤ 0 als (primitiven) Basisfall und überlegen Sie sich
das Induktionsprinzip für die restliche Rekursion!
I Beachten Sie, dass stoff und preise.length nicht gleich sein müssen!
I Sie dürfen KEINE Klassen oder Methoden aus der Java-API verwenden (auch NICHT
System.out.println)! Ihre Klasse muss genau die oben genannten Methoden haben. Sie
dürfen also keine weiteren Methoden oder Attribute (auch keine privaten) deklarieren.

Gruppenaufgabe 4.3: KenKen™ 19 GP


Eine Variante von Sudoku heißt KenKen. Das Rätsel besteht aus einer (n × n)-Matrix M, die durch
dickere Umrandung zu unterschiedlichen Partitionen Pi zusammengefasst werden. Jedem Pi ist eine
Operation Oi ∈ {+, −, ×, ÷, ' '} und deren Endergebnis Ri zugeordnet. Das KenKen ist gelöst,
wenn in jeder Spalte bzw. jeder Zeile jeweils alle Zahlen von 1 bis n genau einmal so vorkommen,
dass sich bei Anwenden von Oi auf alle Zahlen in Pi das angegebene Ri ergibt. Beispiel:

KenKen K Eine Lösung für K Datenstruktur (int[][][])


Jede der im Folgenden zu entwickelnden Methoden wird mit einem int[][][]-Feld aufgerufen,
das ein KenKen-Problem repräsentieren soll. Eine korrekte Datenstruktur hat folgenden Aufbau:
Jeder Eintrag enthält die Beschreibung einer Partition Pi als 2D-int[][]-Feld. Der erste Eintrag
für jede einzelne Partition Pi enthält wiederum ein 1D-int[]-Feld der Länge 2 mit dem (Ri , Oi )-
Paar. Alle weiteren Einträge von Pi sind ebenfalls 1D-int[]-Felder der Länge 2 und enthalten die
Koordinaten eines zu Pi gehörenden Zahlenfeldes der Matrix M in der Form (Zeile, Spalte). Das
Zahlenfeld „oben/links“ in M hat die Koordinaten (0, 0). Erstellen Sie eine Klasse KenKen und
implementieren Sie darin die einzelnen Methoden gemäß ihrer vorgegebenen API wie folgt:
a) Ergänzen Sie zunächst die Methode checkIntegrity(). Sie soll überprüfen, ob das über-
gebene 3D-Array strukturell als KenKen-Problem (wie oben beschrieben und im Beispiel-Bild
gezeigt) interpretiert werden kann.
b) Implementieren Sie nun die Methode checkValidity(). Sie soll überprüfen, ob das über-
gebene 3D-Array semantisch als KenKen-Problem interpretiert werden kann, d.h. ob die Par-
titionen überlappungsfrei sind und insgesamt genau ein quadratisches KenKen abdecken (die
Partitionen selbst müssen dabei nicht zwangsweise zusammenhängend sein).
c) Programmieren Sie schließlich ein rekursives Verfahren zur Lösung eines KenKen-Problems
in solve(). Falls es mindestens eine Lösung gibt, dann soll solve() eine beliebige davon
als quadratisches Array zurückgeben.

-2-
Algorithmen und Datenstrukturen FAU, Informatik 2, AUD-Team
Wintersemester 2018/19 aud@i2.cs.fau.de

Gruppenaufgabe 4.4: Wanderlust 16 GP


Stellen Sie sich vor, Sie planen für die Weihnachtsferien eine Städtereise. Dazu vergeben Sie jeder
Stadt einen Schönheitswert anhand ihrer Attraktionen. Ihr Ziel ist es, einige Städte so zu besuchen,
dass die Summe ihrer Schönheitswerte einen festgelegten Wert genau erreicht. Wenn entsprechende
Wege existieren, kann eine Stadt auch mehrfach (sogar hintereinander) besucht werden.
Die möglichen Städte sind in dieser Aufgabe zur Vereinfachung bei 0 beginnend durchnummeriert.
Für das im öffentlichen Test verwendete Beispiel soll eine Reiseroute mit einem Gesamtwert von
18 gefunden werden, die in Stadt 0 beginnt. Für die gegebenen Städte und Wege gibt es genau zwei
Möglichkeiten: Entweder Sie besuchen Stadt 0 sechsmal hintereinander (6 · values[0] = 6 · 3 = 18)
oder Sie gehen nach Stadt 0 dreimal in die Stadt 3 (values[0] + 3 · values[3] = 3 + 3 · 5 = 18).
Implementieren Sie in einer Klasse Wanderlust exakt die folgenden drei öffentlichen statischen
Methoden (jedoch keine weiteren Methoden oder Attribute!):
a) Erstellen Sie die Methode int solve mit folgenden Parametern in dieser Reihenfolge:
• ReiseCheck rc J Katalog für fertige Reiserouten und Prüfer für Methodenaufrufe
• int[] values J Feld mit den Schönheitswerten der einzelnen Städte (garantiert > 0)
• int[][] next J Feld mit den möglichen Wegen zwischen den Städten (Nachbarn)
Info: next[i][0], next[i][1], . . . sind die Städte, die von Stadt i aus erreichbar sind. Ein
Weg von Stadt i zu Stadt j führt nicht zwangsläufig auch in die Gegenrichtung (Ein-
bahnstraße). Manchmal kann man auch von Stadt i direkt wieder zu Stadt i gelangen.
• int goal J Zielwert für die Schönheitssumme, die noch erreicht werden muss
• int city J Die Stadt, die als nächstes besucht werden soll
Info: Sie und ihr Schönheitswert wurden noch nicht in goal oder path verarbeitet.
• int[] path J Feld mit der gerade zu erstellenden Reiseroute
Info: Das übergebene Feld hat stets genau goal Einträge, die mit −1 initialisiert sind.
• int pathIdx J Position in path, an die die nächste Stadt geschrieben werden soll
Diese Methode soll rekursiv und mittels Backtracking die Anzahl der möglichen Reiserouten
bestimmen und zurückgeben, deren jeweilige Schönheitssumme genau goal ist. Die Städ-
te der jeweils aktuellen Reiseroute sollen dabei in path erfasst werden. Sobald eine gültige
Route gefunden wurde, soll diese mit rc.report(path) in einem Reisekatalog abgelegt
werden. Beim Aufruf von report müssen die ersten Einträge jeweils die Nummern der Städ-
te in Besuchsreihenfolge enthalten – alle weiteren Einträge müssen -1 sein!
Sie dürfen davon ausgehen, dass die übergebenen Werte konsistent sind, d.h. jedes next[i][j]
sowie city sind gültige Indizes im Feld values. Hinweis: Sie sollten mit zunehmenden
Zielwerten (z.B. 150 bis 200) eine stark ansteigende Laufzeit feststellen.
b) Ergänzen Sie die Methode int solveMem(rc, values, next, goal, city, mem).
Sie unterscheidet sich von der Methode solve dadurch, dass die konkreten Reiserouten nicht
mehr gespeichert werden müssen. Gelangt man auf zwei unterschiedlichen Wegen zu einer
Stadt i und sammelt dabei den gleichen Schönheitszwischenwert z ein, dann muss lediglich
einmal berechnet werden, wie viele Möglichkeiten es aus der aktuellen Stadt bis zum Ziel gibt.
Diese Optimierung muss mittels Memoization gelöst werden. Dafür erhält die Methode das
Feld int[][] mem als Parameter: mem[i][w] soll die Anzahl der Routen darstellen, die es
ausgehend von der Stadt i gibt und w Schönheitspunkte wert sind. Anfangs sind alle Einträge
mit −1 („noch nicht berechnet“) vorinitialisiert.

-3-
Algorithmen und Datenstrukturen FAU, Informatik 2, AUD-Team
Wintersemester 2018/19 aud@i2.cs.fau.de

c) Erstellen Sie solveIt(rc, values, next, goal, city) als Variante von solveMem,
die das zweidimensionale und methodenlokale memoization-Feld iterativ (Bottom-Up) befüllt.
Überlegen Sie, in welcher Reihenfolge Sie das Feld bearbeiten müssen, damit Ihnen bei jedem
Eintrag alle nötigen Daten schon vorliegen. Bestimmen Sie die Basisfälle und an welcher Po-
sition im Feld das Endergebnis steht. Iterative Top-Down-Implementierungen sind verboten.

ACHTUNG – WICHTIG:
I Rufen Sie gleich zu Beginn JEDER Ihrer Methoden unbedingt einmal rc.check() auf. Die-
ser Aufruf dient der automatischen Überprüfung/Bewertung Ihrer Implementierung!
I Sie dürfen KEINE Klassen oder Methoden aus der Java-API verwenden (auch NICHT
System.out.println)! Ihre Klasse muss genau die oben genannten Methoden haben. Sie
dürfen also keine weiteren Methoden oder Attribute (auch keine privaten) deklarieren.

25 EP + 35 GP = 60 Punkte

-4-