Vous êtes sur la page 1sur 9

TD 1 : Programmation dynamique

Recherche opérationnelle S3.


2020

Exercice 1 — L’argent de poche

Un étudiant désire travailler en dehors de ses heures de cours pour gagner de l’argent de poche.
Afin de ne pas compromettre ses études, il décide de consacrer un maximum de T heures par
semaine à ses activités rémunératrices. Après de minutieuses recherches, il a trouvé n emplois pos-
sibles. Les salaires qui lui sont offerts ne sont pas proportionnels aux nombres d’heures de travail.
Le tableau ci-dessous donne le salaire s(i, j) de l’emploi i si on travaille j heures. T et n sont pris
égaux à 4
Emploi
Emploi I Emploi II Emploi III Emploi IV
heures de travail : x
0 0 0 0 0
1 26 23 16 19
2 39 36 32 36
3 48 44 48 47
4 54 49 64 56

1. Pouvez-vous aider cet étudiant, en écrivant un algorithme naïf récursif, à déterminer quelle
rémunération maximale il peut espérer ?
2. En déduire un algorithme de programmation dynamique, version mémoïsation, pour résoudre
ce problème. Utilisez cet algorithme sur l’exemple.
3. Ecrire enfin la version itérative de l’algorithme de programmation dynamique. Utilisez cet
algorithme sur l’exemple.
4. Quelles sont les complexités des 3 algorithmes ?
5. On souhaite, en plus de déterminer la rémunération optimale, savoir combien d’heure l’étu-
diant doit effectuer dans chaque emploi. Comment faire ?

I Correction
La solution optimale de cette instance, sauf erreur, est 85 : 2 heures IV, 1 heure II et 1 heure I.
1. Un algorithme naïf pourrait, par exemple, énumérer, pour chaque emploi, le salaire obtenu
en fonction du nombre d’heures. Mais il est démandé un algorithme récursif.
On pose Pocket(h, i) égale au salaire max perçu en travaillant, de manière optimale, h
heures dans les emplois 1 à i. On cherche donc Pocket(T, n) pour résoudre le problème.
On peut trivialement initialiser Pocket(h, 1) = s(h, 1) pour tout h. On peut aussi initialiser
Pocket(0, i) = 0, mais c’est facultatif. Pocket peut se calculer récursivement avec la
formule suivante :

Pocket(h, i) = max Pocket(k, i − 1) + s(h − k, i)


k=0..h

On peut l’interpréter ainsi : si je travaille h heures dans les emplois 1 à i. Alors, nécessairemet,
il existe k ≤ h tel que je travaille k heures dans les emplois 1 à i − 1 et (h − k) heures dans
l’emploi i. Il me suffit donc de trouver le k qui maximise cette somme.
1: function Pocket(h, i)
2: Si i = 1 Alors
3: Renvoyer s(h, i)
4: Si h = 0 Alors

1
5: Renvoyer 0
6: Renvoyer max Pocket(k, i − 1) + s(h − k, i)
k=0..h

2. On en déduit donc qu’on peut recoder cet algorithme en verion mémoïzation en utilisant un
tableau auxilliaire Ar : J0; T K × J1; nK → N. (J’ai appelé ce tableau T dans le cours mais T
est déjà pris ici.)
Ce tableau est initialement vide.
1: function PocketM emo (h, i)
2: Si Ar(h, i) est vide Alors
3: Si i = 1 Alors
4: Ar(h, i) ← s(h, i)
5: Sinon Si h = 0 Alors
6: Ar(h, i) ← 0
7: Sinon
8: Ar(h, i) ← max PocketM emo (k, i − 1) + s(h − k, i)
k=0..h
9: Renvoyer Ar(h, i)
Sur l’exemple, voici ce que donne cet algorithme. On indique ci après les valeurs de Ar ainsi
que les valeurs de h et i de tous les appels récursifs en cours, sous forme d’un encadré.
Je détaille bien le début, un peu moins la fin. Je vous invite à ne pas recopier 15 fois le
tableau, je le fais ici mais, en TD, vous pouvez modifier le tableau dynamiquement.

i i i
1 2 3 4 1 2 3 4 1 2 3 4
h h h
0 0 0 0 0
1 1 1 ?
2 2 2
3 3 3
4 ? 4 ? 4 ?
i i i
1 2 3 4 1 2 3 4 1 2 3 4
h h h
0 0 0 0 0 0 0 0 0 0
1 ? 1 ? ? 1 ? ?
2 2 2
3 3 3
4 ? 4 ? 4 ?
i i i
1 2 3 4 1 2 3 4 1 2 3 4
h h h
0 0 0 0 0 0 0 0 0 0 0 0
1 26 26 26 1 26 26 26 1 26 26 26
2 2 ? 2 ?
3 3 3
4 ? 4 ? 4 ?
i i i
1 2 3 4 1 2 3 4 1 2 3 4
h h h
0 0 0 0 0 0 0 0 0 0 0 0
1 26 26 26 1 26 26 26 1 26 26 26
2 ? 2 ? ? 2 ? ?
3 3 3
4 ? 4 ? 4 ?

2
i i
1 2 3 4 1 2 3 4
h h
0 0 0 0 0 0 0 0
1 26 26 26 1 26 26 26
2 ? ? 2 39 49 49
3 3
4 ? 4 ?
i
1 2 3 4
h
0 0 0 0
1 26 26 26
2 39 49 49
3 ?
4 ?
Je ne continue pas, c’est long, et je suppose que vous avez compris.
i
1 2 3 4
h
0 0 0 0
1 26 26 26
2 39 49 49
3 48 62 65
4 54 75 81 85
Vous pouvez faire remarquer qu’on a pas eu besoin de calculer la 4e colonne.

3. Pour remonter les appels récursifs, on peut se rendre compte que : Pocket(h, i) appelle
Pocket(k, i − 1) pour tout k ≤ h.
Donc si on a calculé Pocket(k, i − 1) pour tout k ≤ T , alors on peut calculer Pocket(h, i)
pour tout h ≤ T .
Les cas terminaux sont les cas où h = 0 et où i = 1.
1: function PocketIter (T, n)
2: Pour i de 1 à n Faire
3: Ar(0, i) ← 0
4: Pour h de 0 à T Faire
5: Ar(h, 1) ← s(h, 1)
6: Pour i de 1 à n Faire
7: Pour h de 1 à T Faire
8: Ar(h, i) ← max Ar(k, i − 1) + s(h − k, i)
k=0..h
9: Renvoyer Ar(T, n)
Sur l’exemple, on obtient le résultat suivant :

Après les lignes 2 et 3 :


i
1 2 3 4
h
0 0 0 0 0
1
2
3
4
Après les lignes 4 et 5 :

3
i
1 2 3 4
h
0 0 0 0 0
1 26
2 39
3 48
4 54
Après les lignes 6, 7 et 8
i
1 2 3 4
h
0 0 0 0 0
1 26 26 26 26
2 39 49 49 45
3 48 62 65 68
4 54 75 81 85

4. On note t1 (T, n) la complexité en temps de l’algorithme de la question 1.


P
On sait que t1 (h, i) = t1 (k, i − 1) et que t1 (h, 1) se fait en temps constant. On va poser
k≤h
t1 (h, 1) = 1.
Du coup on a, par exemple :

t1 (h, 1) = 1
t1 (h, 2) = h
h · (h + 1)
t1 (h, 3) =
2
...

On va montrer que t1 (h, i) = O(hi−1 ) par récurrence. C’est vrai pour i = 1, et si c’est vrai
O(k i−2 ) = O(hi−1 ).
P
pour i − 1 alors, par récurrence, t1 (h, i) =
k≤h
(en toute rigueur, il faudrait faire un peu attention avec ces O et les développer avec leur
constante, mais la preuve est un peu complexe (sans être horrible), je vous invite à aller voir
https://culturemath.ens.fr/content/sommes-des-puissances.)

Pour la version mémoïzation :


On effectue une seule fois les lignes 3 à 8 pour chaque (h, i), pour 2 ≤ i ≤ n et 1 ≤ h ≤ T ,
car les fois suivantes Ar(h, i) est non vide et le Si à la ligne 2 est faux. Donc on effectue au
plus T · n fois les lignes 3 à 8. Donc on effectue au plus T · n la ligne 8 avec ses 0 ≤ h ≤ T
appels récursifs. Il y a donc au plus T 2 · n appels récursifs à PocketM emo .
Preuve courte : Parmi ces appels, il y a au plus T · n appels effectuant les lignes 3 à 8, en
temps O(T ), et au plus T 2 · n − T · n appels ne les effectuant pas en temps O(1). Donc on a
une complexité de l’ordre de O(T 2 · n + T 2 · n − T · n) = O(T 2 · n).
Preuve moins courte : On peut se demander dans la version ci-dessus si on oublie pas
de compter du temps de calcul. Pourquoi les appels effectuant les lignes 3 à 8 se ferait en
temps O(T ) ? En effet, à la ligne 8 on fait des appels récursifs. Donc on met plus de temps
que O(T ) pour effectuer le calcul du max. C’est tout à fait vrai mais ce temps est compté
avec les autres appels récursifs.
Voici un arbre représentant les différents appels quand n = 4 et T = 2

4
i = 4, h = 2 2,3,5,7,8,9

i = 3, h = 2 2,3,5,7,8,9 i = 3, h = 1 2,3,5,7,8,9 i = 3, h = 0
2,3,5,6,9
2,3,5,7,8,9 i = 2, h = 2 i = 2, h = 1 i = 2, h = 0 i = 2, h = 1 i = 2, h = 0
2,3,5,7,8,9 2,3,5,6,9 2,9 2,9

i = 1, h = 2 i = 1, h = 1 i = 1, h = 0 i = 1, h = 1 i = 1, h = 0
2,3,4,9 2,3,4,9 2,3,4,9 2,9 2,9

Dans cet exemple, on a 13 appels récursifs. A côté de chaque appel, on a écrit les lignes
des instructions de l’algorithme effectués pendant l’algorithme. La complexité est le nombre
d’instructions du programme.
Remarque : On pourrait compter le nombre d’instructions sur le dessin, ici 60, mais ce serait
oublier que, une fois qu’on dispose de tous les résultats des appels récursifs, la ligne 8 ne se
fait pas en temps constant mais en temps h + 1 (il y a h + 1 instructions lors de l’appel à la
ligne 8 à cause du max). Il faut donc compter le nombre d’instructions différents de la ligne
8 plus le nombre de lignes 8 fois h + 1. Puisque h ≤ T , Donc au pire 55 + 5(T + 1) = 70
instructions.
Comment calculer cette valeur pour toute valeur de T et de n ? On peut définir deux valeurs
associées à chaque nœud u de l’arbre.
T (u) est le nombre d’instructions effectués pendant l’appel de u, c’est à dire l’ensemble des
instructions accolées à tout le sous-arbre enraciné en u. Par exemple, pour le nœud racine
c’est 70 comme expliqué ci dessus. Pour la feuille i = 1, h = 0 tout en bas sous la racine, c’est
2. Pour le nœud i = 2, h = 2 à gauche, c’est 17 instructions autre que la ligne 8, plus h + 1
soit 20.
S(u) est l’ensemble des instructions associées à un nœud (et pas à ses descendants) : 2 pour
le nœud en bas à droite, 5 pour le nœud i = 3, h = 0 à droite, 8 pour le nœud Pracine (5
instructions hors ligne 8 + 3 instructions pour la ligne 8). On vérifie que T (u) = S(u) où
v>u
v > u signifie que v est un descendant de u dans l’arbre.
Comment compter S(u) en pratique ? Il suffit de calculer la complexité de l’algorithme en
supposant que les appels récursifs se font en temps constant. Cette complexité ne tient donc
pas compte de la complexité des appels récursifs descendants.
La complexité de l’algorithme est T (R) où R est la racine de l’arbre. Donc on cherche la
somme des S(v) pour v > R. Il suffit de compter le nombre de nœuds de l’arbre et de
majorer S(u) pour chaque nœud.
Comme expliqué plus haut, il y a au plus T 2 · n appels récursifs, donc autant de nœuds dans
l’arbre. Parmi ces nœuds, il y en a au plus O(T · n) qui exécuterons les lignes 3 à 8. Tous les
autres n’éxecuterons que les lignes 2 et 9. Pour les derniers, on a donc S(u) = O(1). Pour les
premiers, on a S(u) = O(T ).
Donc T (R) = O(T 2 · n + T 2 ṅ − T · n).

Pour la version Iterative :


La boucle lignes 2-3 se fait en temps O(n). La boucle lignes 4-5 se fait en temps O(n). La
boucle lignes 6-8 se fait en temps O(T 2 · n).
Donc la complexité est également O(T 2 · n).
5. En plus de calculer la rémunération, on va garder en mémoire une information, dans un
second tableau, sur la solution associée au gain optimal.
On crée un second tableau Ar2 . Dans la case Ar2 (h, i), on enregistre toute la solution associée
à Ar(h, i) (mais il existe d’autres méthodes moins coûteuses en mémoire).
On initialise Ar2 trivialement avec Ar2 (h, 1) = (h → 1) pour tout h (ce qui signifie qu’on
travaille h heures dans l’emploi 1) et Ar2 (0, i) = (0 → 1, 0 → 2, . . . , 0 → i) pour tout i (ce
qui signifie qu’on travaille 0 heures dans tous les emplois).
Si k ∗ = arg max Ar(k, i − 1) + s(h − k, i) alors k ∗ est le nombre d’heures qu’il faut travailler
k=0..i
dans les emplois 1 à i − 1 pour maximiser l’argent gagné quand on travaille h heures dans

5
les emplois 1 à i. Donc Ar2 (h, i) = Ar2 (k ∗ , i − 1) ∪ (h − k ∗ → i) ; ce qui revient à dire que
la solution associée à Ar(h, i) consiste à affecter h − k ∗ heures dans l’emploi i puis à affecter
aux autres emplois les mêmes heures que la solution associée à Ar(k ∗ , i − 1).
On a donc les algos suivants :
1: function PocketM emo (h, i)
2: Si Ar(h, i) est vide Alors
3: Si i = 1 Alors
4: Ar(h, i) ← s(h, i)
5: Ar2 (h, i) ← (h → i)
6: Sinon Si h = 0 Alors
7: Ar(h, i) ← 0
8: Ar2 (h, i) ← (0 → 1, 0 → 2, . . . , 0 → i)
9: Sinon
10: k ∗ ← arg max PocketM emo (k, i − 1) + s(h − k, i)
k=0..h
11: Ar(h, i) ← Ar(k ∗ , i − 1) + s(h − k ∗ , i)
12: Ar2 (h, i) ← Ar2 (k ∗ , i − 1) ∪ (h − k ∗ → i)
13: Renvoyer Ar(h, i)

1: function PocketIter (T, n)


2: Pour i de 1 à n Faire
3: Ar(0, i) ← 0
4: Ar2 (h, i) ← (0 → 1, 0 → 2, . . . , 0 → i)
5: Pour h de 0 à T Faire
6: Ar(h, 1) ← s(h, 1)
7: Ar2 (h, i) ← (h → i)
8: Pour i de 1 à n Faire
9: Pour h de 1 à T Faire
10: k ∗ ← arg max Ar(k, i − 1) + s(h − k, i)
k=0..h
11: Ar(h, i) ← Ar(k ∗ , i − 1) + s(h − k ∗ , i)
12: Ar2 (h, i) ← Ar2 (k ∗ , i − 1) ∪ (h − k ∗ → i)
13: Renvoyer Ar(T, n)

Exercice 2 — Distribution de scientifiques à des équipes de recherche

Un projet de recherche spatiale doit résoudre un problème avant que des êtres humains ne
puissent se rendre sur la planète Mars ... Quatre équipes de recherche indépendantes essayent des
approches différentes dans cet objectif. On a estimé que leur probabilité d’échec est de 0.40, 0.60,
0.80, 1.0, respectivement. Ainsi la probabilité qu’aucune des équipes ne réussisse est de 0.40×0.60×
0.80 × 1.0 = 0.192. Comme on cherche à minimiser la probabilité d’échec total, trois scientifiques
de haut niveau ont été affectés au projet.
Le tableau suivant donne les probabilités d’échec de chaque équipe si 0, 1, 2 ou 3 scientifiques
de plus lui sont affectés.
Probabilité d’échec P (i, j)
Nb scientifiques Équipe
I II III IV
0 0.40 0.60 0.80 1.00
1 0.20 0.40 0.50 0.90
2 0.15 0.20 0.30 0.10
3 0.10 0.19 0.20 0.10

1. Pouvez-vous aider à déterminer la probabilité d’échec minimale en écrivant un algorithme


naïf récursif ?
2. En déduire un algorithme de programmation dynamique, version mémoïsation, pour résoudre
ce problème. Utilisez cet algorithme sur l’exemple.

6
3. Ecrire enfin la version itérative de l’algorithme de programmation dynamique. Utilisez cet
algorithme sur l’exemple.
4. Quelles sont les complexités des 3 algorithmes ?
5. On souhaite, en plus de déterminer la probability, savoir où affecter les scientifiques de haut
niveau. Comment faire ?
6. L’équipe 2 a été retirée du projet. Peut-on déduire de la réponse à la question 2 la nouvelle
probabilité d’échec du projet ? Sinon, expliquer succinctement comment procéder ?

I Correction
Cet exo est identique à l’exo 1, la correction est quasiment la même, la formule de la fonction
f change ainsi :
f (i, j) = max f (k, j − 1) · P (i − k, j)
k=0..i
La réponse, sauf erreur, est 0.0096 : 2 scientifiques pour team IV et 1 pour pour la team I.
Le tableau obtenu à l’issue de l’algorithme itératif est :
i
1 2 3 4
h
0 0.40 0.24 0.192 0.192
1 0.20 0.12 0.096 0.096
2 0.15 0.08 0.06 0.0192
3 0.10 0.04 0.032 0.0096
Pour la dernière question, on a la réponse directement si, dans la récurrence, on a ajouté l’équipe
II en tout dernier au lieu de suivre l’order I II III IV (ce qui est très improbable). Sinon, il faut
tout recommencer en supprimant l’équipe II.
Exercice 3 — Le problème de sac à dos

Ce problème fait partie des problèmes classiques de la Recherche Opérationnelle.

Etant donnés un sac à dos de volume total V , n types d’objets, numérotés de 1 à n, avec mi objets
de type i, un volume vi et une utilité ui pour l’objet i.
on souhaite remplir le sac en maximisant l’utilité des objets qu’on y met.
On va utiliser la programmation dynamique pour résoudre ce problème. On définit xi comme
le nombre d’exemplaires de l’objet i mis dans le sac.
1. Donner l’utilité U (x1 , x2 , . . . , xn ) du sac en fonction des objets qu’on a mis dedans.
2. Exprimer la contrainte de volume sous forme V (x1 , x2 , . . . , xn ) ≤ V
On note f (j, b) l’utilité maximale d’un sac de volume b rempli par les j premiers types d’objets
uniquement, pour b ∈ J0, V K et j ∈ J1; nK. C’est à dire la valeur maximale de U (x1 , . . . , xj )
sachant que V (x1 , . . . , xj ) ≤ b.
3. Si quelqu’un nous donne f (j, b) pour tout j et tout b, comment, avec ces données, répondre
au problème de sac à dos ?
4. Donner la valeur de f (1, b) en discutant suivant les valeurs de b.
5. Donner une formule de récurrence permettant de calculer f (j, b) pour j ≥ 2 et tout b.
6. En déduire un algorithme naïf et un algorithme de programmation dynamique version mé-
moïsation pour ce problème. Quels est la complexité de ce dernier ?
7. Ecrire un algorithme de programmation dynamique itératif pour ce problème. Quelle est sa
complexité ?
8. Appliquer l’un des deux algorithmes de programmation dynamique pour résoudre l’exemple
suivant ayant 3 objets et un volume V = 10 :
objet 1 2 3
vi 3 5 2
mi 2 2 4
ui 10 15 8

7
I Correction
n
P
1. L’utilité est U (x1 , x2 , . . . , xn ) = xi · ui .
i=1
n
P
2. Pour le volume : V (x1 , x2 , . . . , xn ) = x i · vi ≤ V .
i=1
3. Il suffit ensuite de renvoyer f (n, V ).
4. f (1, b) consiste à mettre l’objet 1 autant de fois que possible dans volume b :
 
b
f (1, b) = min( , m1 ) · u1
v1
.
5. Si on veut mettre les objets 1 à j dans un sac de volume b, on peut essayer de mettre l’objet j
autant de fois que possible, puis faire un appel récursive avec les objets et le volume restant :

f (j, b) = max
j k f (j − 1, b − k · vj ) + k · uj
b
k=0.. min( vj ,mj )

6. On peut donc déduire les deux algos suivants :


1: function f (j, b)
2: Si j = 1 Alors j k
3: Renvoyer min( vb1 , m1 ) · u1
4: Renvoyer max
j k f (j − 1, b − k · vj ) + k · uj
b
k=0.. min( vj ,mj )

On note T : J1; nK × J0; V K → N un tableau initialement vide.


1: function fM emo (j, b)
2: Si T (j, b) est vide Alors
3: Si j = 1 Alors j k
4: T (j, b) ← min( vb1 , m1 ) · u1
5: Sinon
6: T (j, b) ← max
j k f (j − 1, b − k · vj ) + k · uj
b
k=0.. min( vj ,mj )

7: Renvoyer T (j, b)

On effectue une seule fois les lignes 3 à 6 pour chaque (j, b), car les fois suivantes T (j, b) est
j k au plus V · n fois les lignes 3 à 6. Donc on effectue
non vide et le Si est faux. Donc on effectue
au plus V · n la ligne 6 avec ses min( vbj , mj ) ≤ min(V, max mj ) appels récursifs. Il y a donc
au plus V · n · min(V, max mj ) appels récursifs à fM emo .
Parmi ces appels, il y a au plus V ·n appels effectuant les lignes 3 à 6, en temps O(min(V, max mj )),
et au plus V · n · min(V, max mj ) − V · n appels ne les effectuant pas en temps O(1).
Donc on a une complexité de l’ordre de O(V · n · min(V, max mj )).
7. Pour remonter les appels récursifs, on peut se rendre compte que : f(j, b) peut appeller
f(j − 1, b0 ) pour tout b0 ≤ b.
Donc si on a calculé f(j − 1, b0 ) pour tout b0 ≤ V , alors on peut calculer f(j, b) pour tout
b≤V.
Les cas terminaux sont les cas où j = 1.

1: function fIter (n, V )


2: Pour b ∈ J0; V K Faire
j k
b
3: T (1, b) ← min( v1 , m1 ) · u1

8
4: Pour j ∈ J2; nK Faire
5: Pour b ∈ J0; V K Faire
6: T (j, b) ← max
j k f (j − 1, b − k · vj ) + k · uj
b
k=0.. min( vj ,mj )

7: Renvoyer T (n, V )

La complexité de la boucle 2-3 est O(V ) et la complexité de la bouche 4 − 6 est O(n · V ·


min(V, max mj )).
b
1 2 3 4 5 6 7 8 9 10
j
8. 1 0 0 10 10 10 20 20 20 20 20
2 0 0 10 10 15 20 20 25 25 30
3 0 8 10 16 18 24 26 32 34 36
La réponse est 36 : 2 fois l’objet 3 et 2 fois l’objet 1.
Exercice 4 — Recherche de motif carré

Soit A une matrice n × m constituées de 1 et de 0. Décrire un algorithme permettant de trouver


un carré de 1 de largeur maximum dans A, ainsi que les coordonnées du coin haut gauche de ce
carré. Quelle est la complexité de cet algorithme ?

I Correction
Une bonne réponse consiste à définir f (i, j) comme la taille du plus grand carré de 1 donc le
coin supérieur gauche est (i, j). Dans ce cas, pour trouver la bonne réponse, il faut renvoyer le max
des f (i, j).
Voici une formule de récurrence pour cette fonction :
— f (i, j) = 0 si Ai,j = 0
— f (i, j) = 1 + min(fi+1,j+1 , fi,j+1 , fi+1,j ) sinon
Exercice 5 — Monter des marches

1. Quel est le nombre de manières de monter m marches en les montant une par une et/ou deux
par deux ?
Généralisons. Soit un escalier à m marches. On peut le gravir par différents sauts de α
marches, pour α ∈ {α1 , α2 , · · · , αp }. Par exemple, dans la question 1, on a p = 2, α1 = 1 et
α2 = 2. On va supposer, par commodité, que les αi sont rangés par ordre croissant et sont
tous différents. On appelle N (m) le nombre de manière de monter cet escalier.
2. Donner une formule de récurrence pour N (m).
3. Donner l’algorithme de programmation dynamique associé (en pseudo code) et la complexité
de cet algorithme.
4. Si p = 3, α1 = 2, α2 = 3, α3 = 5, décrivez N (m) pour 0 ≤ m ≤ 12.

I Correction
La réponse à la question 1 est le me nombre f (m) de fibonnaci avec f (0) = 1 et f (1) = 1. En
effet, si on monte 1 marche, il reste alors m − 1 marches et si on en monte 2 d’un coup, il en reste
m − 2. On a donc la formule f (m − 1) + f (m − 2) = f (m) pour m ≥ 2. Si l’escalier a 0 marche, on
a une manière de le monter, c’est de ne rien faire. Si l’escalier a 1 marche, on a une manière de le
monter. P
La généralisation est quasi identique : N (m) = (N (m − αi )).
αi ≤m
On trouve dans l’ordre pour la dernière question : 1, 0, 1, 1, 1, 3, 2, 5, 6, 8, 14, 16, 27

Vous aimerez peut-être aussi