Übungen zu Grundlagen der Programmierung

Werbung
4/1
Technische Universität München
Fakultät für Informatik
Dr. C. Herzog, M. Maalej
WS 2009/10
Lösungsvorschläge zu Blatt 4
16. November 2009
Übungen zu Grundlagen der Programmierung
Aufgabe 14 (Lösungsvorschlag)
Terminierung rekursiver Funktionen Zur Lösung der vier Teilaufgaben suchen wir Eingabewerte,
für die es möglich ist Abstiegsfunktionen, wie in der Vorlesung definiert, anzugeben.
a)
• f_a(m,n) terminiert für alle n ∈ N:
Zum Nachweis der Terminierung für diese Werte wählen wir die Abstiegsfunktion
h : Z × N → N, h(m, n) = n.
Es treten nur für n 6= 0 rekursive Aufrufe auf, d.h. der Parameter n-1 des rekursiven
Aufrufs ist nichtnegativ und es gilt:
h(m + 1, n − 1) = h(m + 2, n − 1) = n − 1 < n = h(n)
• f_a(m,n) terminiert nicht, falls n ∈ Z \ N:
Für n ∈ Z \ N ist n, n-1, n-2, n-3, . . . eine unendliche Folge, in der 0 nicht auftritt. Die
durch den Aufruf f_a(m,n) angestoßene Folge rekursiver Aufrufe f_a(m+1,n-1),
f_a(m+2,n-2), f_a(m+3,n-3), . . . erreicht also niemals den Terminierungsfall
f_a(*,0). Dabei steht * für einen belieben Wert des ersten Parameters.
b)
• f_b(m,n) terminiert für alle (m,n) ∈ Z × Z mit m ≤ n:
Zum Nachweis der Terminierung für diese Werte wählen wir die Abstiegsfunktion
h : Z × Z → N, h(m, n) = n − m.
Es treten nur für n − m 6= 0, d.h. für n − m > 0 im Fall m ≤ n, rekursive Aufrufe auf und
es gilt:
h(m, n − 1) = n − 1 − m = n − m − 1 = h(m, n) − 1 < h(m, n)
h(m + 1, n) = n − (m + 1) = n − m − 1 = h(m, n) − 1 < h(m, n)
• f_b(m,n) terminiert nicht, falls m > n:
Für m > n ist n, n − 1, n − 2, n − 3, . . . eine unendliche Folge, in der m nicht auftritt.
Die durch den Aufruf f_b(m,n) angestoßene Folge rekursiver Aufrufe f_b(m,n-1),
f_b(m,n-2), f_b(m,n-3), . . . erreicht also niemals den Terminierungsfall m == n.
c)
• f_c(m,n) terminiert für alle (m,n) ∈ Z × Z mit m ≤ n und (n − m) mod 2 = 0:
Zum Nachweis der Terminierung für diese Werte wählen wir die Abstiegsfunktion
h : Z × Z → N, h(m, n) = n − m.
Es treten nur für n − m 6= 0 rekursive Aufrufe auf und es gilt:
h(m + 1, n − 1) = n − 1 − (m + 1) = n − 1 − m − 1 = h(m, n) − 2 < h(m, n)
(Achtung: Die Voraussetzung (n − m) mod 2 = 0 stellt sicher, dass mit h(m, n) auch
h(m + 1, n − 1) in N liegt.)
4/2
• f_c(m,n) terminiert nicht, falls m ≤ n und (n − m) mod 2 = 1:
Falls gilt (n − m) mod 2 = 1 (d.h. falls die Differenz n − m ungerade ist), dann bildet
n − m, (n − 1) − (m + 1), (n − 2) − (m + 2), (n − 3) − (m + 3), . . . eine unendliche Folge
ungerader Zahlen, in denen die 0 nicht auftritt. Die durch den Aufruf f_c(m,n) angestoßene Folge rekursiver Aufrufe f_c(m+1,n-1), f_c(m+2,n-2), f_c(m+3,n-3),. . .
erreicht also niemals den Terminierungsfall m==n.
• f_c(m,n) terminiert nicht, falls m > n:
Für m > n ist n − m, (n − 1) − (m + 1), (n − 2) − (m + 2), (n − 3) − (m + 3), . . . eine
unendliche Folge, in der die 0 nicht auftritt. Die durch den Aufruf f_c(m,n) angestoßene Folge rekursiver Aufrufe f_c(m+1,n-1), f_c(m+2,n-2), f_c(m+3,n-3),. . .
erreicht also niemals den Terminierungsfall m==n.
d)
• f_d(n) terminiert für alle n ∈ Z:
Zum Nachweis der Terminierung für diese Werte wählen wir die Abstiegsfunktion
h : Z → N, h(m, n) = |100 − n|.
Es treten nur für n 6= 100 rekursive Aufrufe auf und es gilt:
n < 100 ⇒ h(200 − n − 1) = |100 − (200 − n − 1)| = (200 − n − 1) − 100 = 99 − n
< 100 − n = |100 − n| = h(n)
n > 100 ⇒ h(200 − n + 1) = |100 − (200 − n + 1)| = 100 − (200 − n + 1) = −101 + n
< −100 + n = |100 − n| = h(n)
Aufgabe 15 (Lösungsvorschlag)
a)
f(2,-1)
PPP
PP
PP
PP
f(0,2)
H
H
f(1,2)
f(2,2)
@
@
f(1,1)
f(-1,1)
HH
H
f(0,1)
f(1,1)
@
@
f(0,0)
H
H
HH
f(0,1)
f(1,1)
@
@
f(0,0)
H
f(-1,0)
f(0,0)
@
@
f(-1,-1)
b) Zum Nachweis der Terminierung verwenden wir die Abstiegsfunktion
h : Z × Z → N, h(a, b) = |b − a|.
Es treten nur für |b-a| 6= 0 rekursive Aufrufe auf und es gilt:
Fall a < b:
linker Aufruf: h(a + 1, b) = |b − (a + 1)| = b − (a + 1) = b − a − 1 < b − a = |b − a|
rechter Aufruf: h(a, b − 1) = |(b − 1) − a| = (b − 1) − a = b − a − 1 < b − a = |b − a|
Fall a > b:
linker Aufruf: h(b + 1, a) = |a − (b + 1)| = a − (b + 1) = a − b − 1 < a − b = |a − b| = |b − a|
rechter Aufruf: h(b, a − 1) = |(a − 1) − b| = (a − 1) − b = a − b − 1 < a − b = |a − b| = |b − a|
Für jeden rekursiven Aufruf gilt also die Abstiegsbedingung.
c) Beweis mittels vollständiger Induktion über n = |b − a|
4/3
Induktionsanfang (n = 0):
Sei |b − a| = 0.
Dann gilt a = b und in diesem Fall berechnet sich f(a,b) zu 1 = 20 = 2|b−a| .
Induktionsvoraussetzung: Sei n + 1 = |b − a| > 0 und für alle a0 , b0 mit n = |b0 − a0 | die
Behauptung f(a0 , b0 ) = 2n bereits gezeigt.
Induktionsschritt (n → n + 1):
1. Fall : a < b.
Dann gilt f(a,b) = f(a+1,b) + f(a,b-1). Wegen
|b − (a + 1)| = b − (a + 1) = (b − a) − 1 = |b − a| − 1 = n
und
|(b − 1) − a| = (b − a) − 1 = |b − a| − 1 = n
läßt sich die Induktionsvoraussetzung auf beide rekursive Aufrufe anwenden und
f(a,b) berechnet sich zu 2n + 2n = 2n+1 = 2|b−a| .
2. Fall : a > b.
Dann gilt f(a,b) = f(b+1,a) + f(b,a-1). Wegen
|a − (b + 1)| = a − (b + 1) = (a − b) − 1 = |a − b| − 1 = |b − a| − 1 = n
und
|(a − 1) − b| = (a − b) − 1 = |a − b| − 1 = |b − a| − 1 = n
läßt sich auch hier die Induktionsvoraussetzung auf beide rekursive Aufrufe anwenden und f(a,b) berechnet sich wieder zu 2n + 2n = 2n+1 = 2|b−a| .
Aufgabe 16 (Lösungsvorschlag)
public class Mathdienste {
public int fac (int n) {
return (n == 0) ? 1 : n * fac (n-1);
}
public double power (double x, int n) {
return (n == 0) ? 1 : power(x, n-1) * x;
}
public double expN (double x, int n) {
return (n == 0) ? 1 : power(x,n)/fac(n) + expN(x,n-1);
}
}
public class TestMath {
public static void main (String[] args) {
Mathdienste md = new Mathdienste ();
System.out.println(md.expN(1,5));
}
}
Aufgabe 17 (Lösungsvorschlag)
Markov-Algrithmen
4/4
a)
5
1
2
1
2
(i) εaaaaa ⇒ 0aaaaa ⇒ a1aaaa ⇒ aaa0aaa ⇒ aaaa1aa ⇒
1
4
aaaaaa0a ⇒ aaaaaaa1 ⇒ . aaaaaaa
(ii) Das Ergebniswort besteht aus n + n/2 Zeichen a. Dabei steht der Operand / für die
ganzzahlige Division natürlicher Zahlen.
b)
(i)
→
→
→
→
→
→
→.
→.
→.
→
0a
0b
1a
1b
2a
2b
0
1
2
ε
a1
b0
a2
b1
b0
b2
ε
ε
ε
0
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
(10)
(ii) Nein, da sich Eingabewort und Ergebniswort vom Alphabet her nicht unterscheiden
und somit der Algorithmus immer wieder von vorne beginnen könnte.
Türme von Hanoi
Aufgabe 18
a) Für n = 0 ist die Lösung klar: Es ist nichts zu tun. Hat man bereits eine Zugfolge für n − 1
Scheiben, dann ergibt sich daraus unmittelbar eine Zugfolge für n Scheiben:
(A)
Verlege n Scheiben von a nach b mittels Platz c wie folgt:
Verlege n-1 Scheiben von a nach c mittels Platz b
Setze eine Scheibe vom Platz a auf Platz b
Verlege n-1 Scheiben von c nach b mittels Platz a
Man beachte, dass beim Umlegen der n − 1 oberen Scheiben die unterste nicht stört, weil
sie größer als alle anderen ist.
b) Es wird nur ein elementarer Schritt verwendet: Setze eine Scheibe vom Platz a auf
Platz b.
c) Die Anzahl Anz(n) der benötigten elementaren Schritte, um einen Turm aus n Scheiben zu
versetzen, ist:
Anz(1)
Anz(2)
Anz(3)
Anz(4)
=
=
=
=
1
1+2*Anz(1)
1+2*Anz(2)
1+2*Anz(3)
Anz(n)
=
2n − 1
= 1+2
= 1+2*(1+2)
= 1+2*(1+2*(1+2))
= 1+ 2+ 4+8
d) Das Verfahren ist deterministisch, weil die Schrittfolge eindeutig festgelegt ist. Es ist determiniert, weil das Ergebnis eindeutig ist, es ist terminierend, weil es nach endliche vielen
Schritten endet. Eine andere Lösung: Wir denken uns die drei Plätze im Kreis angeordnet,
und zwar, wenn n ungerade ist, so:
auf a folgt b, darauf c, dann wieder a
4/5
und wenn n gerade ist, so
auf a folgt c, darauf b, dann wieder a.
Das folgende Verfahren gibt für 0 < n die Schrittfolge als Wiederholung von zwei elementaren Schritten an.
(B)
Verlege n Scheiben von a nach b mittels Platz c wie folgt:
Lege die kleinste Scheibe einen Platz weiter
Wiederhole (2^{n-1}-1)-mal:
Bewege eine Scheibe, aber nicht die kleinste
Lege die kleinste Scheibe einen Platz weiter
Im folgenden Beispiel sind Scheiben durch Zahlen dargestellt, die ihre Durchmesser wiedergeben. Fett gedruckt ist jeweils die Scheibe, die zuletzt bewegt wurde. Man beachte, wie
die Turmspitze wandert, und zwar zunächst die 1 nach b, dann 12 nach c, dann 123 nach b
- unabhängig jeweils vom darunterliegenden Rest des Turms:
a
b
c
12345
.....
.....
.2345
....1
.....
..345 ....1 ....2
..345
..... ...12
...45 ....3 ...12
..145 ....3 ....2
..145 ...23
.....
...45 ..123 .....
.....
Dieses Verfahren führt zur selben Schrittfolge und zum selben Ergebnis wie Verfahren (A).
Es ist somit auch deterministisch, determiniert und terminierend.Anmerkung: Der Turm der
buddistischen Mönche, der auf diese Weise täglich um einen Stein versetzt wird und die
Tage bis zum Weltuntergang zählt, hat eine Höhe von 64 Scheiben. Das Umsetzen wird also
mehr als 1015 Jahre dauern. Übrigens ist (264 − 1) auch die Zahl der Reiskörner, die jenem
König dadurch als Belohnung abverlangt wurde, dass er beginnend bei 1 auf jedes folgende
Feld des Schachbretts die doppelte Anzahl Körner legen sollte.
Herunterladen