Récursivité - Corrections

publicité
PC⋆1
Lycée Sainte Geneviève
Récursivité - Corrections
Factorielle
Exercice 3
def factorielle(n):
if n==1:
return 1
else:
return n*factorielle(n-1)
Python
Python
Exercice 1
Lorsqu’il y a appel récursif, la fonction factorielle effectue en plus 2 opérations :
un test et une multiplication. La complexité au rang 𝑛 peut donc s’exprimer en fonction de la complexité au rang 𝑛 − 1 :
Suite de Syracuse
def syracuse(N,k):
if k>1:
print(N)
if N%2==0:
syracuse(N/2,k-1)
else:
syracuse(3*N+1,k-1)
else:
print(N)
𝐶𝑛 = 𝐶𝑛−1 + 2
Avec 𝐶(1) = 1, on obtient :
𝐶𝑛 = 2(𝑛 − 1) + 1
La complexité de la fonction est donc linéaire.
Une fonction mystère
Python
Exercice 2
Cette fonction calcule la somme des chiffres du nombre n. La complexité est linéaire
par rapport au nombre de chiffres de 𝑛.
1
def temps_de_vol(N,k):
if N!=1:
print('u',k,'=',N)
if N%2==0:
temps_de_vol(N/2,k+1)
else:
temps_de_vol(3*N+1,k+1)
else:
print('k=',k)
print('u',k,'=',N)
PC⋆1
Lycée Sainte Geneviève
Exercice 4
Flocon de von Koch
def trace(sequence):
L=len(sequence)
speed(1000)
up()
goto(-250,0)
down()
for lettre in sequence:
if lettre=='A':
forward(10000/L)
elif lettre=='G':
left(60)
elif lettre=='D':
right(120)
mainloop()
1. Au rang 0, la courbe de Koch est constituée d’un unique segment. L’axiome est
donc 𝐴.
On doit ensuite remplacer le segment central d’une ligne droite par un triangle
équilatéral :
𝐴 → 𝐴𝐺𝐴𝐷𝐴𝐺𝐴
Python
Python
2. Pour obtenir la courbe de Koch au rang 𝑛, on appelle la fonction
chaine_rec('A',n).
def chaine_rec(chaine,n):
if n==1:
return chaine
else:
res=[]
for lettre in chaine:
if lettre == 'A':
res+='AGADAGA'
else:
res+=lettre
return chaine_rec(res,n-1)
4. Pour le flocon, la règle de remplacement est la même que pour la courbe, seul
l’axiome est différent. La fonction chaine_rec est inchangée mais est appelée
avec : chaine_rec('ADADA',n)
Exercice 5
Tours de Hanoi
L’hypothèse de récurrence est la suivante :
𝐻𝑛 : On peut déplacer 𝑛 disques du premier vers le dernier piquet.
Pour les figures, on note 𝐴, 𝐵 et 𝐶 les trois piquets de la gauche vers la droite.
L’hypothèse 𝐻1 est vraie :
3. Pour éviter d’avoir un flocon immense aux ordres élevés, on divise la distance
parcourue lorsque la tortue avance par la longueur de la chaine de caractères.
𝐴
2
𝐵
𝐶
𝐴
𝐵
𝐶
PC⋆1
Lycée Sainte Geneviève
Il n’y a besoin que d’un seul mouvement :
Exercice 6
1. Le polynôme résultant du produit est de degré 𝑝 + 𝑞 :
𝐴→𝐶
On suppose maintenant que 𝐻𝑛−1 est vraie (on peut déplacer 𝑛 − 1 disques de 𝐴 vers
𝐶) et on cherche à montrer que 𝐻𝑛 est vraie.
𝐵
𝐶
𝐴
𝐵
Python
𝑛−1
𝐴
Méthode de Karatsuba
𝐶
def produit(P,Q):
p,q=len(P),len(Q)
res=[0]*(p+q)
for i in range(p):
for j in range(q):
res[i+j] += P[i]*Q[j]
return res
Du fait de la double boucle for, la complexité de cette fonction est quadratique.
2. On a :
𝑃𝑄 = (𝑃bas + 𝑋 𝑛 𝑃haut )(𝑄bas + 𝑋 𝑛 𝑄haut )
𝐴
𝐵
𝐶
𝐴
𝐵
𝐶
= 𝑃bas 𝑄bas + 𝑋 𝑛 (𝑃bas 𝑄haut + 𝑄bas 𝑃haut ) + 𝑋 2𝑛 𝑃haut 𝑄haut
= 𝐴 + 𝑋 𝑛 (𝐶 − 𝐴 − 𝐵)𝑃bas + 𝑋 2𝑛 𝐵
Les mouvements nécessaires sont les suivants :
• 𝑛 − 1 disques 𝐴 → 𝐵 ;
3. La méthode récursive consiste à couper les polynômes en deux puis d’utiliser
la fonction pour calculer les produits 𝐴, 𝐵 et 𝐶 sur des polynômes deux fois
plus petit.
• 1 disque 𝐴 → 𝐶 ;
• 𝑛 − 1 disques 𝐵 → 𝐶.
def hanoi(n,A,B,C):
if n==1:
print(A,'->',C)
else:
hanoi(n-1,A,C,B)
print(A,'->',C)
hanoi(n-1,B,A,C)
4. Pour calculer 𝐶 et 𝐶 − 𝐴 − 𝐵, on utilise deux fonctions annexes somme et
différence. On considère que les deux polynômes sont de même longueur.
Python
Python
La condition d’arrêt est obtenue lorsqu’on fait le produit de deux polynômes de
degré 0 : il suffit de faire le produit des deux coefficients.
3
def somme(P,Q):
for idx,elmt in enumerate(Q):
P[idx]+=elmt
return P
PC⋆1
Python
Lycée Sainte Geneviève
5. Pour évaluer la complexité, la récurrence va porter sur 𝑝 et non pas sur 𝑛 :
def difference(P,Q):
for idx,elmt in enumerate(Q):
P[idx]-=elmt
return P
{ 𝐶(1) = 1𝐶(𝑝) = 3𝐶(𝑝 − 1) + 𝛼
On obtient une suite arithmético-géométrique et donc une complexité en 𝑂(3𝑝 ).
Or 𝑝 = log2 (𝑛), donc la complexité est en 𝑂(3log2(𝑛) ).
La courbe ci-dessous compare le nombre de multiplications pour les deux méthodes :
Python
Pour assurer un découpage au même degré, il faut s’assurer que les listes P et Q
ont la même longueur (quitte à remplir avec des 0).
def karatsuba(P,Q):
p,q=len(P),len(Q)
n=max(p,q)
n=n//2+n%2
if p==1 and q==1:
return [P[0]*Q[0]]
else:
#Remplissage des deux listes pour contenir
#le même nombre pair d'éléments
P+=[0]*(2*n-p)
Q+=[0]*(2*n-q)
#Division en 2 des listes P et Q:
P_bas,P_haut=P[:len(P)//2],P[len(P)//2:]
Q_bas,Q_haut=Q[:len(Q)//2],Q[len(Q)//2:]
#Calculs de A, B et C
A=karatsuba(P_bas,Q_bas)
B=karatsuba(P_haut,Q_haut)
C=karatsuba(somme(P_bas,P_haut),
somme(Q_bas,Q_haut))
C=difference(difference(C,A),B)
#Placement des coefficients à la bonne
#position dans B et C
B,C=[0]*2*(n)+B,[0]*(n)+C
return somme(somme(A,C),B)
Ce document est sous licence Creative Commons BY-NC-SA
(attribution, usage non commercial, partage dans les mêmes conditions).
Plus de détails sur http ://creativecommons.org/licenses/by-nc-sa/3.0/fr/
cbna
4
Téléchargement