Feuille 1: Fonctions Récursives

Download Report

Transcript Feuille 1: Fonctions Récursives

MP{931, 932}, PC{933, 934}
Lycée Masséna
Feuille d’exercices 1: Récursivité
Exercice 1. Pour se chauffer .
1. Écrire une fonction récursive calculant la somme des n premiers termes d’une suite arithmétique de premier
terme a et de raison r donnés.
2. Même chose pour une suite géométrique.
3. Écrire une fonction récursive calculant le PGCD de deux entiers positifs (non tous deux nuls) a et b par l’algorithme d’Euclide.
4. Écrire une fonction récursive renvoyant l’inverse d’une chaîne de caractères passée en argument. Par exemple :
>>> inverse("blabla")
>>> inverse("") #chaine vide
>>> inverse("ressasser")
’albalb’
’’
’ressasser’
5. En déduire une fonction palindrome testant si une chaîne est égale à son inverse (elle renvoie un booléen).
Exercice 2. Écrire une fonction récursive base10to2 prenant en entrée un entier positif N , et renvoyant l’écriture
binaire de N sous la forme d’une chaîne de caractères. On renverra la chaîne vide pour zéro.
>>> base10to2(35)
’100011’
Exercice 3. La tête à Toto (un exo IOI).
0 (zéro), ça s’écrit aussi (0 + 0), ou encore ((0 + 0) + (0 + 0)). Écrire une fonction récursive zeros en Python,
prenant en entrée un entier n et affichant à l’écran la chaîne correspondante. Par exemple :
>>> zeros(0)
0
>>> zeros(2)
((0+0)+(0+0))
>>> zeros(4)
((((0+0)+(0+0))+((0+0)+(0+0)))+(((0+0)+(0+0))+((0+0)+(0+0))))
Exercice 4. Calcul de puissances. Cet exercice est classique, et fondamental !
1. Écrire une fonction puissance prenant en entrée deux paramètres x et n et calculant récursivement xn , en
exploitant l’égalité xn = x × xn−1 valable pour tout n ≥ 1. On conviendra que x0 = 1 pour tout réel x.
2. Estimer la complexité de votre fonction.
3. Voici une autre fonction :
def puissance2(x,n):
if n==0:
return(1)
else:
q,r=n//2,n%2
u=puissance2(x,q)
if r==0:
return(u*u)
else:
return(u*u*x)
Démontrer la terminaison et la correction de puissance2.
Svartz
Page 1/4
2014/2015
MP{931, 932}, PC{933, 934}
Lycée Massena
4. Montrer que puissance2 s’exécute en temps O(ln(n)) (en termes d’opérations arithmétiques).
5. Montrer comment calculer le n-ième terme de la suite de Fibonacci en temps O(ln(n)). On pourra penser
matriciellement.
Exercice 5. Les Tours de Hanoï. Le but de cet exercice est de résoudre le problème classique des Tours de Hanoï.
On dispose de trois emplacements et sur le premier se trouve n disques de taille 1, . . . , n formant une tour. Le but du
jeu est de déplacer entièrement la tour sur le troisième emplacement, en déplaçant les disques un à un. La contrainte
est la suivante : n’empiler un disque que sur un emplacement vide ou un disque de taille supérieure.
1. Résoudre le problème pour n = 1, 2, 3.
2. Écrire une fonction récursive résolvant le problème. Votre fonction devra afficher à l’écran une suite de mouvements de la forme i -> j où i et j sont deux éléments distincts de {1, 2, 3}. La signification du mouvement
est la suivante : déplacer le disque en haut de l’emplacement numéro i sur l’emplacement numéro j. Si i
et j sont deux variables contenant des chiffres, on pourra afficher le mouvement demandé par la commande
print("{} -> {}".format(i,j)) ou encore print(i,"->",j).
3. Quelle est la complexité de votre fonction ?
4. Á partir de quel entier n dépasse-t-on la limite du nombre d’appels récursifs imbriqués en Python ?
Exercice 6. Fonctions mutuellement récursives. Démontrer la terminaison et la correction des deux fonctions cidessous.
def impair(n):
if n==0:
return(False)
else:
return(pair(n-1))
def pair(n):
if n==0:
return(True)
else:
return(impair(n-1))
Exercice 7. La fonction d’Ackerman. On définit la fonction d’Ackerman en Python de la façon suivante :
def ack(m,n):
if m==0:
return(n+1)
elif n==0:
return(ack(m-1,1))
else:
return(ack(m-1,ack(m,n-1)))
1. Donner des formules pour ack(0, n), ack(1, n), ack(2, n) et ack(3, n), pour tout entier n ≥ 0.
2. Démontrer la terminaison de la fonction d’Ackermann. On pourra utiliser le résultat suivant : l’ordre lexicographique sur des couples de N2 défini par :
(m, n) ≤ (m0 , n0 )
⇐⇒
m < m0
ou (m = m0 et n ≤ n0 )
ne possède pas de suite infinie strictement décroissante.
Exercice 8. Flocon de Von Koch. Le but de cet exercice est de tracer une ligne brisée qui s’approche de l’objet fractal
appelé le Flocon de Von Koch. La figure ci-dessous montre l’étape élémentaire de tracé de la ligne brisée : on remplace
un segment de droite par le même segment, avec un triangle équilatéral qui a « poussé » du milieu vers l’extérieur.
Pour tracer le flocon, on part d’un triangle équilatéral, et on applique cette transformation sur ses trois côtés. On
obtient ainsi une ligne brisée constituée de 12 segments. On réitère le procédé sur ces 12 segments, etc... La figure
ci-dessous montre les étapes 1, 2 et 3 (l’étape 0 n’est pas représentée).
Svartz
Page 2/4
2014/2015
MP{931, 932}, PC{933, 934}
Lycée Massena
Étape 1
Étape 2
Étape 3
Le flocon de Von Koch n’est autre que la « figure limite » (dans un sens mathématique bien défini) obtenue après
une infinité d’itérations. On se propose d’écrire une fonction récursive en Python, prenant deux paramètres longueur
et n et permettant de tracer la figure obtenue après n itérations, chaque segment ayant une longueur longueur (pour
les figures ci-dessus, longueur est divisée par 3 à chaque fois pour obtenir des figures de même taille). Pour ce faire,
on peut utiliser le module turtle, qu’on importera en tapant
from turtle import *
Dans le module on dirige un robot, qui part du point (0, 0) avec pour angle initial zéro. La commande forward(d)
permet de faire avancer le robot d’une distance d. Les commandes left(a) ou right(a) font tourner le robot d’un
angle a (exprimé en degré) vers la gauche ou vers la droite. Ainsi, la séquence suivante :
forward(200)
left(120)
forward(200)
left(120)
forward(200)
permet de tracer un triangle équilatéral de côté 200 (ce qui permet d’y voir quelque chose).
Ecrire une fonction flocon permettant de réaliser la figure après n itérations, chaque segment ayant la longueur
longueur.
Exercice 9. Algorithme de Strassen. On cherche à multiplier rapidement deux matrices carrées à coefficients dans un
anneau commutatif A quelconque, et on considérera les opérations dans A comme unitaires.
1. Quelle est, en nombre d’opérations dans A, la complexité du calcul du produit de deux matrices A et B de taille
n × n à coefficients dans A, à l’aide des formules classiques ? Écrire une fonction prod_matrices prenant en
entrée deux matrices qu’on supposera de même taille et qui retourne le produit. Une matrice est stockée sous la
forme de la liste de ses lignes, par exemple :

1
M = 4
7
2
5
8
M=[[1,2,3],
[4,5,6],
[7,8,9]]

3
6 
9
En particulier, on accède au coefficient en case (i, j) de M par M[i][j]. Attention, lignes et colones sont indexées
à partir de 0. On récupère la taille d’une matrice carrée via len(M).
2. Vérifiez les formules suivantes, valables pour deux matrices de taille 2, 2.
a1,1 a1,2
b1,1 b1,2
P1 + P4 − P5 + P7
P3 + P5
×
=
a2,1 a2,2
b2,1 b2,2
P2 + P4
P1 − P2 + P3 + P6
où :
P1
P2
P3
P4
P5
P6
P7
=
=
=
=
=
=
=
(a1,1 + a2,2 )(b1,1 + b2,2 )
(a2,1 + a2,2 )b1,1
a1,1 (b1,2 − b2,2 )
a2,2 (b2,1 − b1,1 )
(a1,1 + a1,2 )b2,2
(a2,1 − a1,1 )(b1,1 + b1,2 )
(a1,2 − a2,2 )(b2,1 + b2,2 )
3. En déduire un algorithme récursif (on ne demande pas de le coder !) pour multiplier deux matrices carrées, qui
exploite une stratégie diviser pour régner. C’est l’algorithme de Strassen (1969).
Svartz
Page 3/4
2014/2015
MP{931, 932}, PC{933, 934}
Lycée Massena
4. Justifier que la complexité C(n) de l’algorithme vérifie (en nombre d’opérations dans A) :
n
+ O(n2 )
C(n) = 7 × C
2
5. Qu’en déduisez-vous sur la complexité de l’algorithme de Strassen ?
6. Imaginons qu’on sache multiplier deux matrices de taille 3×3 avec p multiplications. Quel est la valeur maximale
de p qui permettrait de faire mieux (asymptotiquement) que l’algorithme de Strassen ?
Il est conjecturé que pour tout > 0, il existe un algorithme permettant le calcul de deux matrices n×n nécessitant
O(n2+ ) opérations dans A. La meilleure borne connue aujourd’hui (obtenue cette année !) est = 0.3726639.
La question de la complexité du produit de deux matrices est un problème crucial : on peut montrer que de
nombreux problèmes (résolution de systèmes linéaires, inversion de matrices...) ont la même complexité. En
pratique, seul l’algorithme de Strassen est utilisable (pour faire mieux que l’algorithme naïf ) pour des tailles de
matrices réalistes. Le nombre minimal de multiplications nécessaires pour multiplier deux matrices carrées de
taille 3 est également un problème ouvert.
Figure 1 – Une autre fractale
Svartz
Page 4/4
2014/2015