3 Complexiteexo
3 Complexiteexo
albert
1. Donner un exemple d’algorithme dont la complexité spatiale vérifie une relation t(n) = t(n − 1) + t(n − 2) + f (n)
On suppose que f est positive croissante d’ordre polynomial. Chercher une estimation asymptotique de t.
Solution proposée
On pose vk = u2k et on a vk = 4vk−1 + 22k , d’où u2k = vk = (u1 + k)22k .
let u_2(n) =
let v = make_vect (n+1) 0 in
v.(0) <- 1;
for i=1 to n do v.(i) <- v.(i/2) + v.(i/3) done;
v.(n)
;;
Solution proposée
Pn 3k+2
On pose u(n) = t(n)/5n d’où t(n) = 5n [7 + k=1 5k
] = O(5n ).
c(2k )
On résout pour n = 2p . On pose v(k) = 2k log2 7
. On trouve c(n) = Θ(nlog2 7 ).
L. Albert Exos Complexité 2
Indications
Définition récursive brute :
9. Vous vous trouvez face à un mur, trop haut et trop lisse pour que vous puissiez l’escalader. À gauche comme à
droite, le mur semble continuer jusqu’à l’infini. Vous savez qu’une porte est percée dans ce mur, mais vous ne savez
pas si elle est à votre gauche ou à votre droite, vous ne connaissez même pas la distance d à laquelle elle se trouve de
vous ; et la porte est à peine visible, si bien qu’il faut être juste devant elle pour la voir. Décrire une stratégie vous
permettant de trouver cette porte, tout en parcourant une distance O(d).
Solution proposée
Parcourir un km vers la gauche, revenir au point de départ ; parcourir deux km vers la droite, revenir au point de
départ ; et ainsi de suite en doublant à chaque fois la distance. Soit n tel que 2n < d 6 2n+1 ; au pire, on devra
parcourir 2(1 + 2 + . . . + 2n+1 ) + d = 2n+3 − 2 + d < 9d.
10. Soit n > 1 un entier. Le but de l’exercice est d’évaluer le nombre de multiplications requises pour calculer an
connaissant a. Ainsi, on peut calculer a10 en 4 multiplications de la façon suivante : a.a = a2 , a2 .a = a3 , a3 .a2 = a5 ,
a5 .a5 = a10 . On note P (n) le nombre minimal de multiplications requises pour calculer la puissance n-ième d’un
nombre et B(n) le nombre de bits égaux à 1 dans la représentation de n en base 2.
1o Établir les inégalités :
- (1) P (nm) 6 P (n) + P (m),
- (2) dlog2 ne 6 P (n) 6 blog2 nc + B(n) − 1
2o a. En déduire les valeurs de P (n) pour n différent de 7 et inférieur ou égal à 10 en justifiant votre calcul.
b. Montrer que P (15) 6 5. En déduire que l’inégalité P (n) 6 blog2 nc + B(n) − 1 n’est pas optimale.
Solution proposée
Cette fonction calcule le couple (minimum, maximum) d’une liste. On prouve le résultat par récurrence immédiate
sur la longueur de la liste considérée.
La complexité de cette fonction en nombre de comparaisons vérifie c(0) = c(1) = 0 et c(n) 6 2 + c(n − 1). On en
déduit que c(n) = O(n) (plus précisément ∀ n > 2, c(n) 6 2(n − 1)).
La complexité linéaire était attendue (il faut de toute façon lire toute la liste). La complexité est ici inférieure à
celle de l’algorithme naı̈f qui agit en deux passes. Il existe des raffinements de cet algorithme pour faire diminuer les
constantes (cf. cours).
L. Albert Exos Complexité 4
12. La fonction Caml suivante utilise une méthode diviser pour régner en vue de calculer la plus petite et la plus
grande composante d’un vecteur d’entiers :
let minmax t =
let rec minmax_rec t i j =
if i=j then (t.(i),t.(i))
else if i+1=j then begin
if t.(i)<t.(j) then (t.(i),t.(j))
else (t.(j),t.(i))
end
else let k=(i+j)/2 in
let (min1,max1) = minmax_rec t i k
and (min2,max2) = minmax_rec t (k+1) j in
((min min1 min2),(max max1 max2))
in minmax_rec t 0 (vect_length t - 1);;
Justifier la validité de cette fonction puis, notant Cn le nombre de comparaisons entre éléments de t effectuées lorsque
la fonction est appliquée à un vecteur de n éléments, déterminer des constantes a et b optimales telles que :
∀n > 2 : an 6 Cn + 2 6 bn
Solution proposée
La suite (Cn )n>1 est définie par :
(Dn ) est une suite croissante comme on le vérifie sans peine par récurrence.
L’examen de la suite de terme général Dnn (avec Maple par exemple) suggère les valeurs a = 32 et b = 35 .
Le cas minimal semblant être atteint pour (D2n ). Le calcul fournit D2n = 3 · 2n−1 , ∀ n > 1. On vérifie ensuite par
3
récurrence (forte1 ) que ∀ n > 2, Dn > n.
2
k := iquo(n, 2);
if type(n, odd) then u(k) + u(k + 1)
else 2*u(k)
end if
end if
end proc
Solution proposée
15. En considérant qu’il y a 256 caractères possibles on veut comparer 2 textes composés de n caractères. On les
compare jusqu’à épuiser une chaine ou trouver 2 caractères différents. Majorer le nombre moyen de comparaisons à
effectuer pour comparer 2 textes de longueur au plus n.
16. 1o Quelle est la complexité du calcul d’un déterminant d’ordre n, développé récursivement suivant la première
colonne ?
2o Quelle est cette complexité temporelle si on mémorise tous les déterminants mineurs, afin d’eviter de les
calculer plusieurs fois ? Quelle est alors la complexité spatiale ?
17. La multiplication classique de deux matrices 2 × 2 requiert 8 multiplications et 4 additions scalaires, la multi-
plication de deux matrices n × n nécessitant O(n3 ) opérations arithmétiques. Le nombre de multiplications peut être
réduit à l’aide du paradigme diviser pour régner.
2 Celui qui réalise |liste1 | = |liste2 | à 1 près.
L. Albert Exos Complexité 7
1o L’algorithme de Strassen repose sur la décomposition des deux matrices à multiplier en 4 blocs :
µ ¶ µ ¶
A B E F
M= , N= ,
C D G H
µ ¶
−P2 + P4 + P5 + P6 P1 + P2
La matrice produit vaut M N = avec :
P3 + P4 P1 − P3 + P5 − P7
P1 = A(F − H),
P2 = (A + B)H,
P3 = (C + D)E,
P4 = D(G − E),
P5 = (A + D)(E + H),
P6 = (B − D)(G + H),
P7 = (A − C)(E + F ).
P = P1 + X M P2 Q = Q1 + X M Q2
n = aB m + b m = cB m + d
Solution proposée
L. Albert Exos Complexité 8
P
1o Le calcul du produit naı̈f nécessite deux boucles for imbriquées (une par ) et le nombre de multiplications
élémentaires est (degP + 1)(degQ + 1) soit O(N 2 ).
2o a. La résolution de cette équation de récurrence est un classique du cours : on trouve C 0 (N ) = O(N log2 4 ) =
O(N 2 ). On n’a donc rien gagné en ordre de grandeur par rapport à la méthode brutale.
Remarque(s). Comme c’est la première fois dans cette épreuve, vous avez tout intérêt à redémontrer le
résultat du cours. Il faudra donc
– commencer par signaler que la fonction C 0 (N ) est croissante en fonction de N .
– supposer donc dans un premier temps que N = 2p
– poser up = C 0 (2p ) et déterminer up
– enfin conclure dans le cas général pour N par monotonie (i.e. en encadrant).
b. Cette fois ci C 00 vérifie :
C 00 (N ) = 3C 00 (dN/2e) + O(N )
On obtient donc C 00 (N ) = O(N log2 3 ) et log2 3 ' 1, 58.
3o Dans le cas d’entiers, apparaissent les retenues qui n’existaient pas au niveau des polynômes. Cela ne change
pas le nombre de multiplications élémentaires mais complique quelque peu la vie au programmeur.
Notons finalement que si on compare dans la pratique la multiplication naı̈ve des grands entiers avec la multipli-
cation de Karatsuba, le gain en complexité ne se fait sentier que pour de très grands entiers...
19. On suppose connue une fonction ppcm2 qui calcule le ppcm de 2 entiers. On veut généraliser cette fonction
au calcul du ppcm de n entiers. Proposer une solution Caml itérative et une solution Caml récursive à l’aide d’une
méthode ”diviser pour régner”. Comparer les performances des deux approches.
On convient que 1 est toujours un minimum local de α. Exprimer le nombre de comparaisons effectuées par
l’algorithme précédent en fonction du nombre k de minima locaux de la permutation α.
b. On note par un,k le nombre de permutations sur n éléments qui présentent k minima locaux. Montrez que :
un,0 = 0 un,n = 1
Donnez une expression de Pn (x) comme un produit de monômes du premier degré. Montrez que la dérivée
Pn0 (x) satisfait µ ¶
0 1 1 1
Pn (x) = Pn (x) + + ... +
x x+1 x+n−1
d. Donnez une expression du nombre moyen Mn de minima locaux dans les permutations sur n éléments.
e. Quel est le comportement à l’infini du nombre moyen de comparaisons dans le programme de l’étudiant ;
le comparer à 3n
2 .
Solution proposée
1o On suggère
let minmax v =
let n = vect_length v in let mini = ref v.(0) and maxi = ref v.(0) in
for i = 1 to (n/2) do
if v.(2*i) <= v.(2*i-1) then begin
if v.(2*i) < !mini then mini := v.(2*i);
if v.(2*i-1) > !maxi then maxi := v.(2*i-1)
end else begin
if v.(2*i) > !maxi then maxi := v.(2*i);
if v.(2*i-1) < !mini then mini := v.(2*i-1)
end
done;
if (n mod 2)=1 then (min !mini v.(n-1),max !maxi v.(n-1))
else (!mini, !maxi);;
On vérifie ensuite par induction sur la longueur du vecteur que cette fonction est correcte.
On effectue 3E(n/2) comparaisons plus 1 éventuellement si v est de longueur impaire.
2o a. Pour chaque i entre 1 et n-1 il y a 2 comparaisons si i n’est pas un minimum local et une seule s’il en est
un. Comme le nombre de minimum locaux de la permutation qui appartiennent à 1,2, ... n-1 est k-1 le nombre
de comparaisons effectuées par l’algorithme vaut :
2(n − 1 − (k − 1)) + k − 1 = 2n − k − 1
b. Toute permutation admet au moins un minimum local ainsi un,0 = 0. Pour qu’une permutation a1 , a2 , ...
an présente n minima locaux il faut que a1 > a2 > . . . > an il n’y en a donc qu’une seule ainsi un,n = 1.
Soit α une permutation sur n éléments qui présente k minima locaux. En supprimant n de la suite, on obtient
une permutation β sur n − 1 éléments. Celle-ci présente k − 1 minima locaux si n se trouvait en tête et k
minima sinon. Réciproquement étant donnée β il y a n − 1 façons d’insérer n autrement qu’en tête et une
seule de l’insérer en tête pour obtenir α. Ainsi :
c. On multiplie par xk l’égalité ci-dessus et on somme ces égalités pour k = 1, 2...n, on obtient
e. Le nombre moyen de comparaisons de l’algorithme proposé est ainsi de 2n − ln(n) prépondérant devant
3n/2.
21. Soit x1 , x2 , . . ., xn une suite finie de nombre entiers non tous nécessairement distincts. La ”multiplicité” d’une
valeur x dans la suite est égale au nombre de fois où x apparaı̂t dans la suite. Un entier z est dit ”valeur majoritaire”
si sa multiplicité est supérieure ou égale à n/2 + 1.
1o Montrer que si xi est différent de xj et si l’on supprime xi et xj de la suite, la valeur majoritaire de la suite
initiale, s’il en existe une, est aussi valeur majoritaire de la suite obtenue après suppression.
2o Montrer qu’en examinant successivement les éléments de la suite dans l’ordre x1 , x2 , . . ., xn , on peut ”mettre
à jour” deux variables C et M ayant la propriété suivante :
lorsque l’on considère xi , C contient une valeur qui est la seule candidate possible à être valeur majoritaire parmi
x1 , x2 , . . ., xi−1 et M contient le nombre de fois où la valeur C est apparue jusqu’alors, si l’on exclue les fois où
C a été éliminé.
3o En déduire un algorithme qui, en deux ”parcours” de la suite x1 , x2 , . . ., xn détermine si la suite possède ou
non une valeur majoritaire et donne cette valeur majoritaire quand elle existe.
Solution proposée
1o On considère une liste d’entiers L de longueur n (implémentée par exemple sous la forme d’un vecteur) qui a
(ou non) une valeur majoritaire m.
Considérons les deux premiers éléments de la liste x1 et x2 et notons L0 la liste L privée de x1 et x2 (de longueur
n − 2). Dans cette question on traite le cas où x1 6= x2 .
Si x1 et x2 sont tous les deux différents de m, on peut les supprimer de la liste : la nouvelle liste L0 a toujours m
pour valeur majoritaire (m est même encore plus majoritaire !).
Si un des deux vaut m, le nombre d’occurrences de m dans L0 a diminué de 1 mais la nouvelle longueur est n − 2
donc m est encore majoritaire dans L0 .
Conclusion : en supprimant les deux éléments de tête d’une liste dans le cas ou ceux-ci sont différents, on ne
change pas la valeur majoritaire d’une liste, si elle existe. Remarquons (en prenant par exemple la liste [1 ;2 ;3])
que cette suppression peut conduire à l’apparition d’une valeur majoritaire dans L’ (ici 3) alors qu’il n’y en avait
pas dans L.
2o C est ainsi le candidat pour être une valeur majoritaire de la liste L dont on a lu les i premiers éléments. On
initialise C et M avec x0 et 1. On procède par examen successif des éléments de la suite. Quand on considère xi
on le compare à C et on ajoute ou on enlève 1 à M selon que xi est égal ou non à C. Lorsque M devient nul c’est
qu’il n’y avait pas de valeur majoritaire dans le début de la liste et on donne alors à C la valeur xi+1 et à M la
valeur 1.
À la fin du parcours, il ne reste qu’un candidat C. On fait alors un deuxième parcours de la suite pour déterminer
son nombre d’occurrences dans L et décider si oui ou non c’est bien une valeur majoritaire.
La complexité de notre algorithme est ainsi bien linéaire.
(* valeur majoritaire *)
let x=[|1;2;5;1;3;2;4;7;6;4;2;2;0|];;
let y=[|1;2;5;2;2;2;4;2;6;4;2;2;0|];;
let candidat_val_maj x =
let C= ref x.(0) and M = ref 1 in
for i =1 to (vect_length x) -1 do
if x.(i) = !C then M:=!M+ 1
else M:= !M-1;
if !M=0 then begin C:=x.(i) ; M:=1 end
done;
!C;;
let valmaj x =
L. Albert Exos Complexité 11
let C = candidat_val_maj x in
let M = ref 0 in
for i =0 to (vect_length x) -1 do
if x.(i) = C then M:= !M+1
done;
if !M>((vect_length x) / 2) then C else -1;;
valmaj x;;
valmaj y;;
Soit E un ensemble de points dont on a calculé la décomposition en tranches E = T1 ∪ T2 ∪ . . . ∪ Tk dont les pivots
ont pour ordonnées y1 , y2 , . . . , yk . Soit Q = (x, y) un point du plan dont l’abscisse est strictement plus petite que
les abscisses de tous les points de E et dont l’ordonnée n’est égale à aucune des ordonnées des points de E.
3o Montrez que si y > y1 alors Q est un point maximal de E 0 = E ∪ {Q}. Montrez qu’il existe un point de Tj qui
domine Q si et seulement si y < yj .
4o Dans quel cas E 0 a-t-il une tranche de plus que E ?
5o En déduire un algorithme qui détermine la décomposition en tranches de E 0 connaissant celle de E et les
ordonnées des pivots de E.
6o Comment réaliser alors la décomposition en tranches d’un ensemble E donné ?
2o Écrire une fonction decoupe X Y Yp deb fin qui place dans Yp[deb...med] les points de X[deb...med] classés
par ordonnées croissantes et dans Yp[med + 1...fin] les points de X[med + 1... fin] classés par ordonnées croissantes,
deb + f in
où med est la partie entière de . On a donc coupé suivant les abcisses notre ensemble de points en deux
2
moitiés où les points sont rangés suivant leur ordonnée.
Évaluer le nombre de transferts effectués lors de l’utilisation de cette fonction (il doit être linéaire !).
3o On suppose que A et B sont les points les plus proche de X[deb...med] et, C et D sont les points les plus
proches de X[med + 1 ... fin].
Ecrire un algorithme linéaire qui détermine les deux points les plus proches de l’ensemble X [deb ... fin] connaissant
A, B, C, D et Y[deb ... fin]. (on montrera que l’on peut se limiter à considérer les points d’une bande médiane,
où chaque point est considéré avec au plus 7 autres points de la bande).
4o En déduire une fonction cherche récursive qui répond à notre problème avec une complexité Θ(n ln n).
24. On considère le ”jeu des chiffres” dans lequel on donne une suite w[1], w[2], .... w[n] de
P n nombres entiers (int
de Caml) et un nombre s. On demande de trouver un sous-ensemble I des indices tel que i∈I w[i] = s.
Donner un algorithme résolvant ce problème. Quelle est sa complexité ?
Indications
Proposer une solution récursive utilisant le fait qu’un algorithme A(s, k) (qui résout le problème de somme s en
utilisant w[k], ..., w[n]) vérifie A(s, k) = A(s, k + 1) ou A(s − w[k], k + 1) suivant que dans la solution on utilise ou
non w[k].
Solution proposée
let w=[|2;4;8;12;25;7|];;
25. À chaque exécution de la procédure Hanoı̈ on associe une chaı̂ne de caractères de la façon suivante :
– Un déplacement d’une rondelle du piquet 1 vers le piquet 3 est noté par le symbole a,
– du piquet 1 vers le piquet 2 par le symbole b
– et du piquet 2 vers le piquet 3 par c.
Les déplacements inverses sont notés par les mêmes lettres avec une barre dessus (ā, b̄, c̄). Ainsi la chaı̂ne de caractères
correspondant au déplacement de deux rondelles du piquet 1 vers le piquet 3 selon l’algorithme décrit en cours est :
h2 = bac. Celle correspondant au déplacement de trois rondelles du piquet 1 vers le piquet 3 est :
h3 = abc̄ab̄ca
4o Montrez que lorsque l’on supprime les barres au dessus des caractères intervenant dans la chaı̂ne hn on obtient
une chaı̂ne très régulière.
5o En déduire une procédure itérative permettant de résoudre le problème des tours de Hanoı̈.
26. Soit P un polygône à n sommets notés dans l’ordre Ai , i = 0 . . . n − 1, leurs coordonnées étant (xi , yi ) (les
indices se comprennent modulo n).
Pn−1
On note p = i=1 d(Ai−1 , Ai ) le périmètre de P . Le but est de déterminer le couple (Ai0 , Aj0 ) découpant P en deux
parties de longueurs les plus semblables possibles. Ce couple est réalisé par :
¯ ¯
¯j−1 i+n−1 ¯
¯X X ¯
inf ¯¯ d(Ak , Ak+1 ) − d(Ak , Ak+1 )¯¯
(i,j) ¯ ¯
k=i k=j
On suppose donnés n: int et P : (int * int) vect tel que P.(i) contienne les coordonnées de Ai .
1o La force brute.
a. Écrire une fonction dist_plus renvoyant
j−1
X
dist plus(i, j) = d(Ak , Ak+1 )
k=i
et dist_moins renvoyant
i+n−1
X
dist moins(i, j) = d(Ak , Ak+1 )
k=j
et conclure à un algorithme permettant de trouver la paire (i0 , j0 ). Quelle est l’ordre de grandeur de sa
complexité (en appels à d) ?
2o Amélioration de l’algorithme.
L. Albert Exos Complexité 14
a. Écrire une fonction qui à i donné renvoit Opposé(i), ce dernier étant le plus grand j > i tel que
j−1
X p
d(Ak , Ak+1 ) 6
2
k=i
Écrire un programme renvoyant un vecteur J et un vecteur D tel que J.(i) = Opposé(i) mod n et D.(i) =
d(Ai , AOpposé(i) ).
Quelle est sa complexité ? Peut-on s’arranger pour avoir une complexité en O(n) ? (remarquer que Opposé(i
+ 1) succède à Opposé(i) mod n).
b. Montrer que j0 = J.(i0 ) ou (J.(i0 ) + 1) mod n. Conclure à un nouvel algorithme permettant de trouver
(i0 , j0 ). Quelle est sa complexité ?
Solution proposée
let n=6;;
let P=[|0.,2.; 0.,0.; 3.,1. ; 4.,3.; 4.,4. ; 2.,5.|];;
let dist_suiv i =
let (x,y) = (point i) and (u,v) = (point (i+1)) in
norme ((x -. u),(y -. v));;
let distance i j =
let d = ref 0.0 in
if (i >= j) then 0.0 else
( for k = i to j-1 do d:= !d +. (dist_suiv k);done; !d; );;
let dist_plus i j =
if (j < i) then (distance i (j+n)) else (distance i j);;
let M =
let m = (make_matrix n n 0.0) in
for i = 0 to (n-1) do
for j = 0 to (n-1) do
m.(i).(j) <- abs_float ((dist_plus i j) -. (dist_moins i j)); done; done;
m;;
let (i0,j0) =
let point = ref (1,1) and d = ref (dist_moins 1 1) (* soit p *) in
for i = 0 to (n-1) do
for j = i to (n-1) do
if (M.(i).(j) <. !d) then (d:=M.(i).(j); point:=(i,j))
done; done;
!point;;
(* calcul de p *)
let p = let d = ref 0.0 in for i = 0 to (n-1) do d:= !d +. (dist_suiv i);done; !d;;
L. Albert Exos Complexité 15
let oppose i =
let j = ref i and d = ref 0.0 and psur2 = (p /. 2.0) in while (!d <=. psur2) do
(d:= !d+.(dist_suiv !j);
j:= !j+1;) done; (* j vaut oppose(i) +1 *)
(!j - 1) mod n;;
(* calcul de D et J *)
for i = 1 to n-1 do
D.(i) <- D.(i-1) -. (dist_suiv (i-1));
J.(i) <- J.(i-1);
while ((D.(i) +. (dist_suiv J.(i)))<=. psur2) do
D.(i) <- D.(i) +. (dist_suiv J.(i));
J.(i) <- (J.(i)+1) mod n;done; (* J.(i) est calcul’e *)
done;;
D;;J;;
res;;
27. On peut programmer le tri fusion avec un nombre de comparaison qui vérifie la relation
CN = Cbn/2c + Cdn/2e + N
PN −1
A partir d’un calcul de CN +1 − CN , Montrer que CN = k=0 (bln2 k + 2c)
En déduire que CN = N dln2 N e + N − 2dln2 N e
– on place tour à tour chacun des 6 mots dans la corbeille correspondant à sa dernière lettre ; cela donne : P1 = {321},
P2 = {112, 232, 312} et P3 = {113, 233}.
On récupère ensuite, dans cet ordre, les mots et la nouvelle suite S1 de mots à traiter est ainsi : 321, 112, 232,
312,113, 233.
– on place ensuite chacun des 6 mots dans la corbeille suivant sa deuxième lettre ; cela donne : P1 = {112, 312, 113},
P2 = {321} et P3 = {232, 233} (l’ordre relatif dans S1 de deux mots ayant la même deuxième lettre n’a pas été
modidié).
La nouvelle suite S2 de mots à traiter est cette fois : 112, 312, 113, 321, 232, 233.
– Enfin on itère le procédé sur la première lettre ; on a : P1 = {112, 113}, P2 = {232, 233} et P3 = {312, 321}.
Et la suite finale triée est bien : 112, 113, 232, 233, 312, 321.
1o Justifier la validité de l’algorithme.
2o Proposez des structures de données ad hoc pour traiter le problème.
3o Donner une version Caml de l’algorithme (on pourra utiliser le type prédéfini queue).
4o Quel est sa complexité en fonction de N et n ? Ce résultat vous surprend-il ?
Solution proposée
1o On peut faire une récurrence sur N :
– Pour des mots d’une lettre, l’algorithme effectue un tri en une itération.
– On suppose qu’après la i-ième étape les mots sont correctement triés dans la suite Si suivant leurs i dernières
lettres. La (i+1)-ième étape classe alors les mots suivant la lettre suivante (la (N-i)-ième) et, puisqu’en cas
d’égalité elle ne modifie pas l’ordre des mots de Si , les mots sont correctement rangés suivant leur (i+1)
dernières lettres dans Si+1 .
2o On choisit par commodité de représenter chaque mot par un vecteur d’entiers. L’algorithme nécessite de
connaitre toute la suite de mots dès le départ : on choisit également une structure vectorielle pour S. Chaque
corbeille doit recevoir les mots en conservant leur ordre d’arrivée : on choisit donc une structure FIFO, les files
(queue en Caml).
3o Voici une solution Caml :
let L= [| [|1;1;2|] ; [| 3; 2; 1|] ; [|1;1;3|] ; [|2;3;2|] ; [|2;3;3|] ; [|3;1;2|] |];;
let N=3;;
#open "queue";;
let p1 = new ()
and p2 = new ()
and p3 = new ();;
(* les files de rangements *)
let ajoute i e =
match e.(i) with
| 1 -> add e p1
| 2 -> add e p2
| _ -> add e p3 ;;
let merge v =
L. Albert Exos Complexité 17
let tri_mecano v =
for i=(N-1) downto 0 do
tri_indice i v; merge v
done; v;;
4o On a vu dans le cours que la complexité optimale en moyenne et dans le cas le pire d’un tri par comparaisons
d’une suite de n mots est en n log n. Ici l’exécution d’une passe de tri a un coût linéaire en n et l’on effectue N
itérations soit un coût total en nN . Ceci n’a rien de surprenant :
– d’une part on sait que si les données à trier ne sont pas quelconques (par exemple évoluant dans un ensemble
de cardinal fini connu d’avance), on peut les trier avec un coût linéaire en temps (mais linéaire en espace
également),
– d’autre part l’ordre lexicographique à ceci de particulier qu’il ne nécessite pas la connaissance de toutes les
lettres pour comparer deux mots.
let CFR t =
let rec CFR_aux u i j =
if i=j then () else
if i+1=j then begin if u.(i)>u.(j) then \’{e}change u i j end else
let k=(j+1-i)/3 in
CFR_aux u i (j-k); CFR_aux u (i+k) j; CFR_aux u i (j-k)
in CFR_aux t 0 (vect_length t - 1);;
1o Montrer que le programme précédent est correct, id est : il trie bien le tableau transmis en argument, dans
l’ordre croissant de ses valeurs.
On se propose d’analyser cette méthode. Soit Cn le coût maximal exprimé en nombre de comparaisons d’éléments
du tableau, lorsque la taille de celui-ci est n.
2o Écrire des relations qui permettent de calculer, de proche en proche, les valeurs de Cn .
3o Compléter le tableau suivant des premières valeurs de Cn :
n 1 2 3 4 5 6 7 8 9 10
Cn 0 1 3 9 27 ? ? ? 81 243
4o Montrer qu’à partir d’un rang n0 que l’on précisera, on a Cn > n2 .
5o A-t-on ∀ n > 1, Cn 6 n3 ?
6o Justifier : il n’existe aucun exposant α tel que Cn soit équivalent à nα lorsque n tend vers l’infini.
L. Albert Exos Complexité 18
7o (difficile) exhiber un exposant β tel que Cn = o(nγ ) pour tout γ > β, et nγ = o(Cn ) pour tout γ < β.
Solution proposée
Le tri selon les Pieds Nickelés.
1o La fonction trie en place les deux premiers tiers du vecteur, puis les deux derniers et recommence le tri des
deux premiers tiers.
Prouvons sa validité par récurrence sur j − i > 1 : pour j − i = 1 et j − i = 2, c’est clair. Sinon, supposons la
fonction correcte pour j − i 6 n et prouvons qu’elle l’est encore pour j − i = n + 1. Notons k la partie entière de
n/3 ; on a 3k 6 n, donc n − 2k > k. Après le premier appel récursif, les k plus grand éléments sont dans t[i + k..j] ;
après le deuxième appel, ils sont à leur place dans t[j − k + 1..j]. Enfin, le troisième appel trie t[i..j − k].
2o C1 = 0, C2 = 1 et Cn = 3Cn−bn/3c pour n > 2.
3o À l’aide de la fonction Maple suivante (dopée par l’option remember) :
c := proc(n) option remember; 3*c(n-iquo(n,3)) end;
c(1) := 0; c(2) := 1;
on a déterminé les résultats :
n 1 2 3 4 5 6 7 8 9 10
Cn 0 1 3 9 27 27 81 81 81 243
4o En fait, Maple permet de constater que les seules valeurs de n 6 1000 telles que Cn < n2 sont 1, 2, 3, 4 et 6.
Soit p > 3 tel que Cn > n2 pour tout n ∈ [[2p, 3p − 1]]. Alors :
3(xn − 1) 3xn − 1
< xn+1 6
2 2
3
On en déduit la majoration xn+1 − 1 6 2 (xn − 1) d’où
µ ¶n−3
3 3n−3 3n−3
xn − 1 6 (x3 − 1) = n−4 soit xn 6 1 + n−4
2 2 2
L. Albert Exos Complexité 19
puis, dans une deuxième passe, on s’en sert pour calculer la place finale de ai par :
Indications
let m = 6;;
(* les entiers \‘{a} trier sont < 6 *)
let distribution a =
let n = vect_length a in
let b = make_vect n 0 in
let c = make_vect m 0 in
for i=0 to (n-1) do c.(a.(i)) <- c.(a.(i)) + 1 done;
for j=1 to m-1 do c.(j) <- c.(j-1) + c.(j) done;
for i=(n-1) downto 0 do
b.(c.(a.(i))-1) <- a.(i);
c.(a.(i)) <- c.(a.(i)) -1
done;
b;;
31. Quelques compléments sur la fonction d’Ackermann (voir le polycop de cours pour sa définition).
Par commodité d’écriture nous noterons A(n, p) pour ackermann n p.
1o Donner les expressions explicites de A(1, p), A(2, p) et A(3, p).
2o Que vaut A(4, 4) ? Comparer cet entier avec 1080 (qui est une estimation du nombre d’atomes de l’univers !).
L. Albert Exos Complexité 20
Solution proposée
La fonction d’Ackermann.
1o Calcul de A(1, p).
On a A(1, 0) = A(0, 1) = 2 et A(1, p + 1) = A(0, A(1, p)) = A(1, p) + 1 donc par récurrence A(1, p) = p + 2.
Calcul de A(2, p).
On a A(2, 0) = A(1, 1) = 3 et A(2, p + 1) = A(1, A(2, p)) = A(2, p) + 2 donc par récurrence A(2, p) = 2p + 3.
Calcul de A(3, p).
On a A(3, 0) = A(2, 1) = 5 et A(3, p + 1) = A(2, A(3, p)) = 2A(3, p) + 3 donc par récurrence A(3, p) = 2p+3 − 3.
2o On a A(4, 4) = 2A(4,3)+3 − 3 > 2A(4,3) d’où, comme A(4, 0) = 13 > 2, on a :
à ³ ¡ ¢´!
22
2
2
A(4, 4) À 2 = 265536 À 1080 !
ó¡ ¢´!
213
2
2
Exactement, A(4, 4) = 2 − 3.
3o On va montrer le résultat par induction dans (N2 , 4) suivant le théorème de correction. Soit pA le prédicat
défini pour tout (n, p) ∈ N2 par : pA (n, p) = ”A(n, p) > p”.
- Si n = 0, alors A(0, p) = p + 1 > p, soit pA (0, p).
- Par définition, A(n, 0) = A(n − 1, 1). Par hypothèse d’induction, on a A(n − 1, 1) > 1 donc on a bien A(n, 0) =
A(n − 1, 1) > 1 > 0.
- Par définition, A(n, p) = A(n−1, A(n, p)). Par hypothèse d’induction, A(n, p−1) > p−1 et A(n−1, A(n, p−1)) >
A(n, p − 1) donc A(n, p) = A(n − 1, A(n, p − 1)) > A(n, p − 1) > p − 1 d’où A(n, p) > p (on travaille dans N !).
On a donc bien montré pA pour tout (n, p) ∈ N2 .
4o Il suffit de montrer que ∀ (n, p) ∈ N2 , A(n, p + 1) > A(n, p). C’est clair si n = 0. Soit n ∈ N∗ , on a, pour tout
p, d’après la question précédente, A(n, p + 1) = A(n − 1, A(n, p)) > A(n, p) soit le résultat.
5o On va montrer le résultat à nouveau par induction. Soit pA le prédicat défini pour tout (n, p) ∈ N2 par :
pA (n, p) = ”A(n + 1, p) > A(n, p)”.
- Si n = 0, alors A(1, p) = p + 2 > A(0, p) = p + 1.
- Par définition, A(n + 1, 0) = A(n, 1). Par hypothèse d’induction, A(n, 1) > A(n − 1, 1) d’où A(n + 1, 0) =
A(n, 1) > A(n, 0) = A(n − 1, 1).
- Par définition, A(n, p) = A(n − 1, A(n, p)). Par hypothèse d’induction, A(n + 1, p − 1) > A(n, p − 1) d’où, d’après
la question précédente, A(n − 1, A(n + 1, p − 1)) > A(n − 1, A(n, p − 1)). Et, par induction on peut supposer
A(n, A(n + 1, p − 1)) > A(n − 1, A(n + 1, p − 1)) et on en déduit bien
6o Pour vérifier la définition de α, il suffit de montrer que la suite (A(n, n))n∈N tend vers +∞. On a A(0, 0) = 1,
A(1, 1) = 3, A(2, 2) = 7, A(3, 3) = 61 et A(4, 4) = ... Pour n > 3, en utilisant les questions précédentes,
A(n + 1, n + 1) = A(n, A(n + 1, n)) > A(n + 1, n) > A(n, n), d’où la stricte croissance de la suite et le résultat
s’en déduit.
La fonction α est évidemment une fonction à la croissance très lente. Elle intervient notamment dans le calcul
de la complexité du problème Set-Union-Find (union et recherche dans les ensembles). On connaı̂t en effet un
algorithme d’union d’ensembles 3 ”quasi-linéaire” (de complexité O(n α(n))).
On pourra se reporter au problème de Mathématiques appliquées et Algorithmique posé en 1995 à l’ENS de Lyon
(attention, pour simplifier les calculs, l’auteur a choisi une définition de Ackermann légèrement différente de la
définition usuelle).
z| }|
{z }{