Rekursion Dubbel Algoritmkonstruktion Rekursiv lösningsstrategi Vanliga strategier Brute-Force (ren råstyrka) Gå igenom alla fall Greedy (girig strategi) Välj nästa steg efter vad som lokalt verkar bäst Exempelproblem Hitta största elementet i en sekvens v i där i 1... n Antag att vi redan känner m = max v i i 1... n 1 Lösningen blir då det största elementet av m och v n Divide-and-Conquer (söndra och härska) Bryt sönder problemet i mindre delar Sekvensen blir mindre i en Bestäm ett basfall för en liten sekvens Sekvenser med ett element: max[v 1 ] = v 1
Rekursiv lösningsstrategi Rekursiv lösningsstrategi def max( v ) : i f l e n ( v ) == 1 : return v [ 0 ] m = max( v [ 1 : ] ) i f v [ 0 ] > m: return v [ 0 ] return m Problem Beräkna n-fakultet: n! = i 1...n Antag att vi redan känner (n 1)! Lösningen blir då n! = n (n 1)! i Talen blir mindre i en Bestäm ett basfall för en litet tal 0! = 1 Rekursiv lösningsstrategi def f a c t ( n ) : return n f a c t ( n 1) def exp ( b, n ) : return b exp ( b, n 1)
def exp ( b, n ) : tmp = exp ( b b, n //2) i f n%2 == 1 : return b tmp return tmp Kombinatoriskt problem På hur många sätt kan en kedja med n länkar nå d steg bort? n = 10 Dubbel d = 5 Antag att vi redan vet svaret för n 1 Dubbel Rekursionsformel Dubbel n = 9, d = 5 f (n, d) = f (n 1, d 1) + f (n 1, d) + f (n 1, d) n = 9, d = 4 n = 9, d = 5 d < 0 0 n < d 0 n = d 1 d = 5
def f o l d ( n, d ) : i f d < 0 : i f n < d : i f n == d : return \ f o l d ( n 1, d 1) + \ 2 f o l d ( n 1, d ) Dubbel Kombinatoriskt problem På hur många sätt kan man växla en hundring? Antag att det finns obegränsade mängder av bestämda valörer, t.ex. 50-lappar, 20-lappar, 10-kronor, 5-kronor, enkronor. Ordningen på valörerna är irrelevant. Dubbel Dubbel Rekursionsformel Dubbel Antag att vi redan vet svaret för alla mindre belopp än 100 kr. Antag även att vi redan vet svaret för färre valörer, t.ex. när det inte finns några 50-lappar. f (a, m) = f (a, m[1..n]) + f (a m 0, m) där a är önskat belopp och m är en lista med valörer. Två disjunkta fall: 1. Alla sätt att växla där första valören används 2. Alla sätt att växla utan första valören a < 0 0 a = 0 1 m = [] 0
def change ( amount, c o i n s ) : i f amount < 0 : i f amount == 0 : i f l e n ( c o i n s ) == 0 : return \ change ( amount, c o i n s [ 1 : ] ) + \ change ( amount c o i n s [ 0 ], c o i n s ) Dubbel >>> import change >>> change. change (100, (50, 20, 10, 5, 1 ) ) 343 Dubbel def change ( amount, c o i n s, used ) : i f amount < 0 : return [ ] i f amount == 0 : return [ used ] i f l e n ( c o i n s ) == 0 : return [ ] return \ change ( amount, c o i n s [ 1 : ], used ) + \ change ( amount c o i n s [ 0 ], c o i n s, \ used +[ c o i n s [ 0 ] ] ) Dubbel Hur hittar man stora primtal? lilla sats Om p är ett primtal så gäller: a p mod p = a 1 a < p Observation: Om p inte är ett primtal så gäller oftast a p mod p a Prova med flera a. Risken att alla passerar testen för ett icke-primtal är minimal.
from random import r a n d i n t def f e r m a t t e s t ( p, a ) : return a p % p == a Problem a p är ett orimligt stort tal för stora p def i s P r i m e ( p ) : f o r i i n range ( 1 0 ) : i f not f e r m a t t e s t ( p, r a n d i n t ( 2, p 1)): return F a l s e return True Lösning Alla delberäkningar kan utföras modulo p. def expmod ( b, n, m) : tmp = expmod ( b b % m, n //2, m) i f n%2 == 1 : return ( b tmp ) % m return tmp