¢¡¤£¦¥¤§© ¤

Werbung
http://www.mpi-sb.mpg.de/~hannah/info5-ws00
R
S
IS
UN
WS 2000/2001
E R SIT
S
Bast, Schömer
SA
IV
A
Grundlagen zu
Datenstrukturen und Algorithmen
A VIE N
Lösungsvorschläge für das 3. Übungsblatt
Letzte Änderung am 14. November 2000
Aufgabe 1
(a) Bei einer Addition zweier n × n-Matrizen werden n2 primitive Additionen benötigt. Für eine
Multiplikation zweier n × n-Matrizen werden n2 · n = n3 primitive Multiplikationen und
n2 · (n − 1) primitive Additionen, also 2n3 − n2 primitive Operationen benötigt.
(b) Behauptung: Für n = 2k , k ∈ , berechnet der Algorithmus das Produkt C zweier n × nMatrizen A und B korrekt. Also cij = (A · B)ij für alle i, j = 1, ..., n
Zunächst kann man durch Ausmultiplizieren feststellen, daß die Formeln auf dem Übungsblatt stimmen. Beispiel:
M1 + M 2 − M 4 + M 6
= (A12 − A22 )(B21 + B22 ) + (A11 + A22 )(B11 + B22 ) − (A11 + A12 )B22 + A22 (B21 − B11 )
= A12 B21 + A12 B22 − A22 B21 − A22 B22 + A11 B11 + A11 B22 + A22 B11 + A22 B22
−A11 B22 − A12 B22 + A22 B21 − A22 B11
= A11 B11 + A12 B21 .
Weiter betrachten wir zwei Fälle.
1. Fall: n = 2: Die Matrizen A und B bestehen aus vier ganzen Zahlen. In diesem Fall
berechnet der Algorithmus offensichtlich das korrekte Ergebnis.
2. Fall: n > 2: Für i,j = 1, ..., n/2 ist nach dem Strassen-Algorithmus
(C11 )ij = (A11 · B11 + A12 · B21 )ij = (A11 · B11 )ij + (A12 · B21 )ij .
Nach Konstruktion sind A11 , B11 , A12 und B21 Matrizen der Größe n/2 × n/2 mit
(A11 · B11 )ij =
Also
(C11 )ij =
n/2
X
aik bkj
und
k=1
n/2
X
k=1
aik bkj +
n
X
k=n/2+1
(A12 · B21 )ij =
aik bkj =
n
X
k=1
n
X
aik bkj .
k=n/2+1
aik bkj = (A · B)ij
für i,j = 1, ..., n/2.
Analog zeigt man für C12 , C21 und C22 , dass sie die korrekten Teilmatrizen aus A · B liefern.
Analyse: Bei der Multiplikation zweier n×n-Matrizen mit dem Strassen-Algorithmus werden
7 Multiplikationen und 18 Additionen zweier n/2 × n/2-Matrizen benötigt.
(c) Sei G(n) die Anzahl der primitiven Operationen bei der Multiplikation zweier n × nMatrizen. Dann gilt:
1
falls n = 1
G(n) =
7G(n/2) + 18(n/2)2 falls n ≥ 2
Aus dem Master Theorem für Rekursionsgleichungen folgt (a = 7, b = 2, c = 9/2, d = 2,
logb a = log 7 > 2 = d):
G(n) = O(nlog 7 )
Insbesondere ist log 7 < 3, so daß der Strassen-Algorithmus besser ist als der naive Algorithmus.
Aufgabe 2
a) Algorithmus:
bool is_prime(integer m)
{
if (m < 2) return false;
integer i = 2;
while (i * i <= m)
{
if (m % i == 0)
return false;
}
return true;
}
b) Die while-Schleife läuft höchstens
√
// 0,1 keine Primzahlen
// solange i <= Wurzel von m
//
// falls i Teiler von m
// keine Primzahl
// kein Teiler gefunden
m Mal durch; da m < B n also höchstens B n/2 mal.
Ein Durchlauf kostet O(n2 ) primitive Operationen für die Multiplikation zum Testen der
Abbruchbedingung plus O(n2 ) primitive Operationen für die Berechnung des Restes bei der
Division von m durch i (laut Hinweis von der Mailingliste; vgl. Aufgabe 5 vom 1. Übungsblatt).
Zusammen ergibt sich also O(B n/2 · n2 ); um O(B n ) zu zeigen, genügt es also, sich O(n2 ) =
O(B n/2 ) klar zu machen!
Aufgabe 3
a) Schreibe logB (k) =
ln(k)
.
ln(B)
k·
Dann ist zu zeigen:
ln(B)
ln(k)
+
≤k−2
B
ln(B)
für k ≥ 3, B ≥ 14.
Wir zeigen
k·
ln(B)
B
+
ln(k)
ln(B)
ln(k)
k
≤ 2 ln(B)
+ ln(B)
1
k
= ln(B)
+
ln(k)
2
k
1
+
ln(k)
≤ ln(14)
2
≤ k−2
(siehe Teil b))
(siehe Teil c)).
b) Es ist
Wir definieren die Funktion
⇔
⇔
ln(B)
B
2
1
B
2
(ln(B))
− (ln(B))2
1
≤ 2 ln(B)
≤ 12 B
≥ 0.
1
f (x) := x − (ln(x))2
2
und zeigen, daß f (x) ≥ 0 ist für x ≥ 14.
(i) Es ist
1 2 ln(x)
−
2
x
2(ln(x) − 1)
f 00 (x) =
.
x2
f 0 (x) =
(ii) Für x ≥ 14 ist ln(x) ≥ ln(14) > 1. Es folgt
f 00 (x) ≥
2(ln(14) − 1)
>0
x2
für x ≥ 14.
Also ist f 0 (x) für x ≥ 14 monoton wachsend.
(iii) Es ist
f 0 (14) =
1 2 ln(14)
−
> 0.
2
14
Es folgt, daß
f 0 (x) > 0
für x ≥ 14.
Also ist die Funktion f für x ≥ 14 monoton wachsend.
(iv) Es ist
f (14) = 7 − (ln(14))2 = 0.035376 > 0.
Es folgt
f (x) > 0
für x ≥ 14.
c) Zu zeigen ist
k
1
+ ln(k) ≤ k − 2
ln(14) 2
für k ≥ 3. Diese Ungleichung ist äquivalent zu
1
ln(k)
k 1−
−2−
≥ 0.
2 ln(14)
ln(14)
Es sei
1
g(x) = x 1 −
2 ln(14)
−2−
ln(x)
.
ln(14)
Wir zeigen jetzt, daß g(x) > 0 ist für x ≥ 3. Es ist
g 0 (x) = 1 −
Für x ≥ 3 folgt
1
1
−
2 ln(14) x ln(14)
1
1
−
≥ 0.684 > 0.
2 ln(14) 3 ln(14)
Also ist für x ≥ 3 die Funktion g(x) monoton wachsend. Es ist
ln(3)
1
≥ 0.015 > 0.
−2−
g(3) = 3 1 −
2 ln(14)
ln(14)
g 0 (x) ≥ 1 −
Aufgabe 4
Das ε in der Laufzeitabschätzung O(n1+ε ) ist eine Konstante. Diese ist zwar prinzipiell frei wählbar
(vorausgesetzt, sie ist echt positiv), allerdings hängt davon ab, in wieviele Teilstücke ak−1 , . . . , a0 ,
bk−1 , . . . , b0 die Eingabe a, b aufgeteilt wird. Wenn jetzt ε = log1 n gesetzt wird, erhalten wir für
2
jedes n “einen anderen” Algorithmus, da nun auch k nicht mehr konstant ist. Insbesondere werden
sich die Konstanten, die in der O-Notation versteckt sind, ebenfalls ändern.
Etwas formaler läuft die Argumentation so: Für ε → 0 gilt notwendigerweise k → ∞. Im Skript
wird abgeschätzt:
1
k = 2x ⇒ T (n) = O(n1+ x ).
Für
1
x
=ε=
1
log2 n
gilt dann also k = n für alle n.
D.h., jede Eingabe der Länge n wird in n einzelne Bits zerlegt. Die Rekursionsgleichung vereinfacht
sich dadurch zu T (n) ≤ (2n − 1)T (1) + cn. Der entscheidende Punkt ist nun aber, dass c gar
keine Konstante mehr ist, sondern (linear) von n abhängt: Die Rekonstruktion der n Koeffizienten
des Polynoms C geschieht jetzt durch Multiplikation mit der Inversen der (2n − 1) × (2n − 1)Vandermonde Matrix. Statt cn werden nun also Θ(n2 ) Multiplikationen (von höchstens n-stelligen
Zahlen) durchgeführt, also gilt auch T (n) = Ω(n2 ).
Noch etwas genauer: Der verallgemeinerte Algorithmus zerlegt das Problem, zwei n-stellige Zahlen
zu multiplizieren, in 2k − 1 Teilprobleme der Größe k. Das Zerlegen kostet dabei wie schon bei
clever_mult keine primitiven Operationen (man muss ja nur“ shiften). Primitive Operationen
”
werden aber beim Zusammensetzen der Teillösungen benötigt, und zwar bei der Berechnung von




c0
C(0)
 c1 


C(1)



−1 
=
V
·
 .. 

.
..
 . 


.
c2k−2
C(2k − 2)
Wieviele primitive Operationen dabei genau benötigt werden ist gar nicht so einfach zu bestimmen; was man aber sofort sieht ist, dass die C(0), . . . , C(2k − 2) alle höchstens n Stellen (sogar
höchstens 2 · n/k) haben, und dass die Matrix V −1 Θ(k 2 ) Einträge hat. Daraus läßt sich nun
einerseits folgern, dass sich das Matrixprodukt für konstantes k mit O(n) primitiven Operationen berechnen läßt. So wird in den Course Notes argumentiert, und daraus folgt dann auch die
Rekursionsgleichung
T (n) ≤ (2k − 1) · T (n/k) + c · n,
für irgendeine Konstante c, und somit nach dem Master Theorem T (n) = O(nlogk (2k−1) ). Andererseits braucht man auch bestimmt Ω(k 2 ) Operationen, um das Matrixprodukt zu berechnen.
Da man nun, um ε = 1/ log2 n zu erreichen, k = Θ(n) wählen muss (also z.B. k = n, was heißen
würde, dass man a und b in jeweils n einstellige Zahlen aufspaltet), gilt für T , dass
T (n) ≥ (2k − 1) · T (n/k) + c0 · n2 ,
für irgendeine Konstante c0 , und somit bestimmt T (n) = Ω(n2 ) (schon die erste Rekursionsstufe
kostet dann ja Θ(k 2 ) = Θ(n2 ) primitive Operationen). Also nix O(n).
Aufgabe 5
Zuerst überprüfen wir, dass für das D aus dem Hinweis
D=
l
Y
i=1
blog pi nc
pi
≤
l
Y
logpi n
pi
=
i=1
l
Y
n = nl ,
i=1
und weil nach dem Hinweis (Primzahlsatz) l < n/ log4 n ≤ n/ logB n haben wir
D < nn/ logB n = B n ,
d.h. D hat in der Tat höchstens n Stellen (bez. Basis B).
Sei jetzt k ∈ {1, . . . , n} beliebig, und sei pα1 1 · · · pαl l mit αi ∈ 0 die (eindeutige) Primzahlzerlegung
von k (man beachte, dass Primfaktoren größer als n nicht vorkommen können, da k ≤ n). Dann
muss
aber
für jedes i ∈ {1, . . . , l} gelten dass αi ≤ logpi n (sonst k > n) und damit auch αi ≤
logpi n , womit klar ist, dass k ein Teiler von D ist. Alle Zahlen aus {1, . . . , n} sind also Teiler
von D.
Sei jetzt k eine natürliche Zahl mit höchstens 2+dlogB ne Stellen, und damit k ∈ {1, . . . , B 3 n}, und
α
3
sei pα1 1 · · · pl0 l0 die Primzahlzerlegung von k, wobei p1 , . . . , p0l jetzt die Primzahlen aus
{1, . .. , B n}
sind. Dann sieht man leicht, dass k kein Teiler
von D ist genau dann wenn αi ≥ logpi n für ein
0
i ∈ {1, . . . , l } (man beachte dass logpi n = 1 für i > l).
dlogp ne
Für jedes i ∈ {1, . . . , l0 } ist aber pi i ≥ n, so dass in einer Folge von direkt aufeinanderfoldlogp ne
genden Zahlen höchstens jede n-te Zahl durch pi i teilbar sein kann. Für jedes i ∈ {1, . . . , l0 }
dlogp ne
können also höchstens ein n-tel aller Zahlen aus {1, . . . , B 3 n}, also höchstens B 3 , durch pi i
teilbar sein.
Es folgt, dass es in der Menge {1, . . . , B 3 n} höchstens l0 · B 3 Nichtteiler von D geben kann. Da
nach Primzahlsatz l0 < B 3 n/ log4 (B 3 n), sind also höchstens B 3 n · B 3 / log4 (B 3 n) aller Zahlen aus
{1, . . . , B 3 n}, also ein Bruchteil von höchstens O(1/ log n), keine Teiler von D.
Für unseren Checker heißt das, das man nicht einfach, wie man vielleicht intuitiv annehmen
möchte, einen beliebigen zufälligen k-stelligen Modulus wählen darf, für k = 2 + dlogB ne (das n
hier ist das 2n aus der Vorlesung). Die Erfolgswahrscheinlichkeit ist wirklich nur dann so hoch,
wenn man eine zufällige Primzahl wählt. (Man beachte auch, dass die Wahrscheinlichkeit, dass
eine zufällig gewählte k-stellige Zahl eine Primzahl ist, gerade Θ(1/ log n) war.)
Herunterladen