CPGE MP/PSI — Informatique · Calculer chaque sous-problème une seule fois
1 / 12
Le problème de la récursivité naïveMOTIVATION
La suite de Fibonacci : $F_0=0,\ F_1=1,\ F_n=F_{n-1}+F_{n-2}$.
deffib(n):
if n < 2: return n
return fib(n-1) + fib(n-2)
Catastrophe. Le même sous-problème est recalculé des milliers de fois. Complexité exponentielle $O(\varphi^n)$ avec $\varphi\approx 1{,}618$. Pourtant il n'y a que $n+1$ valeurs distinctes !
2 / 12
L'idée centralePRINCIPE
« Ne jamais recalculer deux fois la même chose. » On mémorise le résultat de chaque sous-problème, et on le réutilise.
Pour Fibonacci, la complexité tombe de $O(\varphi^n)$ à $O(n)$.
Intérêt (programme officiel). La programmation dynamique sert à réduire la complexité temporelle de certains problèmes — souvent d'exponentielle à polynomiale.
3 / 12
Les deux ingrédientsCONDITIONS
1. Sous-structure optimale. La solution optimale se construit à partir des solutions optimales des sous-problèmes $\Rightarrow$ on peut écrire une formule de récurrence.
2. Chevauchement des sous-problèmes. Les mêmes sous-problèmes reviennent plusieurs fois $\Rightarrow$ la mémorisation est rentable.
PD vs diviser-pour-régner. Les deux découpent ; mais en « diviser pour régner » les sous-problèmes sont disjoints. La PD n'a d'intérêt qu'avec le chevauchement.
4 / 12
Lien avec les algorithmes gloutonsCOMPARAISON
Glouton
Programmation dynamique
Un seul choix, jamais remis en cause
Examine tous les choix, garde le meilleur
Rapide
Plus coûteuse
Optimal parfois
Toujours optimal
La PD résout exactement les problèmes où le glouton échoue — comme le sac à dos 0/1.
5 / 12
Top-Down : la mémoïsationAPPROCHE 1
Garder la récursion naturelle + un cache.
deffib_memo(n, memo={}):
if n < 2: return n
if n in memo: return memo[n] # réutilise
memo[n] = fib_memo(n-1) + fib_memo(n-2)
return memo[n]
= récursion + cache. On ne calcule que les sous-problèmes utiles. Attention à la profondeur de pile.
6 / 12
Bottom-Up : la tabulationAPPROCHE 2
Partir des plus petits sous-problèmes, remplir un tableau par des boucles.
deffib_tab(n):
if n < 2: return n
f = [0]*(n+1); f[1] = 1for i inrange(2, n+1):
f[i] = f[i-1] + f[i-2]
return f[n]
= boucles + tableau. Pas de récursion (pas de limite de pile) ; calcule tous les sous-problèmes ; il faut le bon ordre de remplissage.
7 / 12
Méthode généraleRECETTE
Le cœur du travail = trouver la récurrence :
définir l'état (que désigne le sous-problème ?) ;
écrire les cas de base ;
exprimer un sous-problème en fonction de plus petits ;
repérer la réponse finale.
Ensuite, au choix : mémoïsation (Top-Down) ou tabulation (Bottom-Up). Même résultat, même complexité.
8 / 12
Le sac à dos 0/1EXEMPLE
$n$ objets $(p_i,v_i)$, capacité $C$, objet pris en entier ou pas. $M(i,c)$ = valeur max avec les $i$ premiers objets et capacité $c$.