Aller au contenu

Numérique et sciences informatiques (spécialité) · TerminaleBac

Programmation dynamique : cours de Terminale NSI

Publié le 7 novembre 2026 · Mis à jour le 7 novembre 2026 · Signaler une erreur

L'essentiel

  • La programmation dynamique découpe un problème en sous-problèmes, règle les plus petits en premier, puis monte vers les plus grands en gardant en mémoire chaque résultat 6.
  • Elle est utile quand les mêmes sous-problèmes reviennent souvent : c'est justement le cas où diviser pour régner perd son efficacité 6.
  • Démarche : définir les sous-problèmes, écrire la relation de récurrence, puis programmer en méthode descendante (mémoïsation) ou ascendante (tableau) 6.
  • Un tableau ou un dictionnaire conserve chaque résultat : chaque sous-problème n'est calculé qu'une seule fois, ce qui ramène Fibonacci d'un coût exponentiel à un coût linéaire.
  • Exemples classiques : suite de Fibonacci, rendu de monnaie, sac à dos, plus longue sous-chaîne commune 26.

Pourquoi une nouvelle méthode ?

Tu connais déjà la méthode diviser pour régner : on coupe un problème en morceaux, on résout chaque morceau, puis on assemble. Le tri fusion en est l'exemple typique. Cette méthode marche très bien quand les morceaux sont indépendants. Mais que se passe-t-il quand deux morceaux demandent de refaire exactement le même calcul ?

C'est le cas qui nous intéresse dans ce chapitre. La programmation dynamique est une technique de conception d'algorithmes, pensée pour les problèmes d'optimisation, qui apparaît au début des années 1950 avec Richard Bellman 6. À l'époque, le mot « programmation » voulait dire planification et ordonnancement, pas écriture de code 6. Le nom peut donc surprendre : il n'a aucun rapport avec une façon de programmer « dynamiquement » en Python.

La méthode a séduit très vite l'industrie, où beaucoup de calculs économiques suivaient cette logique : piloter des procédés chimiques ou gérer des stocks, par exemple 6. Dans le programme de terminale NSI, elle fait partie de la partie algorithmique, aux côtés des algorithmes sur les arbres et les graphes et de la méthode diviser pour régner.

Le problème : des calculs refaits sans fin

Prenons l'exemple classique, souvent utilisé pour introduire le sujet : la suite de Fibonacci 6. Elle est définie par F0=0F_0 = 0, F1=1F_1 = 1 et, pour n≥2n \geq 2, Fn=Fn−1+Fn−2F_n = F_{n-1} + F_{n-2} 6. Les premiers termes sont donc 0,1,1,2,3,5,8,13,21,34,55…0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55\ldots

La définition se traduit tout de suite en fonction récursive :

def fib(n):
    if n == 0 or n == 1:
        return n
    return fib(n - 1) + fib(n - 2)

C'est un algorithme inefficace : quand un même sous-problème se présente plusieurs fois, diviser pour régner perd son efficacité 6. Voyons pourquoi sur F5F_5.

Le remède est simple à énoncer : ne jamais calculer deux fois la même chose. Quand on a trouvé F3F_3, on le range quelque part ; la fois suivante, on le relit au lieu de le recalculer. C'est le cœur de l'idée naturelle sur laquelle reposent la programmation dynamique et la mémoïsation, deux techniques très proches 5.

Les ingrédients de la méthode

Un problème se prête à la programmation dynamique quand deux conditions sont réunies : on peut le découper en sous-problèmes de même nature, et ces sous-problèmes se recoupent (on retombe sur les mêmes). Sans recoupement, le diviser pour régner suffit.

Les étapes de la méthodeQuatre étapes successives : définir les sous-problèmes, écrire la récurrence, choisir le sens du calcul, lire la réponse.1Sous-problèmesDéfinir ce que contient chaque case.2RécurrenceRelier une case à des cases plus petites.3Sens du calculDescendant avec mémoire ou ascendant.4RéponseLire la case du problème initial.
  1. Sous-problèmesDéfinir ce que contient chaque case.
  2. RécurrenceRelier une case à des cases plus petites.
  3. Sens du calculDescendant avec mémoire ou ascendant.
  4. RéponseLire la case du problème initial.
Les étapes de la méthode · Démarche générale d'un algorithme de programmation dynamique.

Méthode descendante : la mémoïsation

La première façon de procéder garde la fonction récursive, mais lui ajoute une mémoire. Avant de calculer, la fonction regarde si la réponse est déjà connue. Si oui, elle la renvoie. Sinon, elle la calcule, la range, puis la renvoie. On part du problème initial (le « haut ») et on descend vers les cas de base : c'est la méthode descendante.

Méthode ascendante : remplir un tableau

La seconde façon renverse le point de vue. Au lieu de partir du haut et de descendre, on part des cas de base et on construit les sous-problèmes des plus petits aux plus grands, dans l'ordre, en remplissant un tableau 6. Il n'y a plus de récursivité : une simple boucle suffit. C'est la méthode ascendante.

Le rendu de monnaie

Passons à un vrai problème d'optimisation. Tu disposes de pièces de valeurs données (par exemple 1, 3 et 4 centimes), en quantité illimitée. Il faut rendre une somme SS avec le plus petit nombre de pièces possible.

Le problème du sac à dos

Le sac à dos (knapsack en anglais) est un grand classique de la recherche opérationnelle 6. On dispose de nn objets, chacun avec un poids wiw_i et une valeur cic_i 4, et d'un sac qui supporte un poids maximal. On cherche à emporter des objets de valeur totale maximale sans dépasser cette capacité.

Tableau du sac à dos de capacité 5
Objets utilisésc = 0c = 1c = 2c = 3c = 4c = 5
aucun000000
A003333
A, B003447
A, B, C003457
Tableau du sac à dos de capacité 5 · Objets A (2 ; 3), B (3 ; 4), C (4 ; 5). La réponse est la dernière case de la dernière ligne : 7.

Plus longue sous-chaîne commune et autres usages

Plusieurs problèmes peuvent être abordés à l'aide de la programmation dynamique. Éduscol s'intéresse notamment à la recherche de la plus longue sous-chaîne commune de deux textes xx et yy 2. Voici l'idée, construite avec nos propres outils.

D'autres usages existent : l'algorithme CYK, qui sert à l'analyse syntaxique, et la détection de ruptures, pour laquelle la programmation dynamique est la méthode la plus utilisée 6.

Quand l'utiliser, et ses limites

Exercices corrigés

Exercice 1 Remplir un tableau de Fibonacci

★☆☆Environ 8 min

On utilise la version ascendante avec tableau f pour calculer F10F_{10}, avec F0=0F_0 = 0 et F1=1F_1 = 1.

  1. Donne le contenu du tableau f une fois la boucle terminée.
  2. Quelle est la valeur de F10F_{10} ?
  3. Combien d'additions la boucle effectue-t-elle pour n=10n = 10 ?
Indice 1

Chaque case, à partir de la case 2, est la somme des deux précédentes.

Indice 2

La boucle commence à i=2i = 2 et finit à i=10i = 10.

Voir la correction pas à pas
  1. On place les cas de base : f[0] = 0 et f[1] = 1.

  2. On calcule dans l'ordre : f[2] = 1, f[3] = 2, f[4] = 3, f[5] = 5, f[6] = 8, f[7] = 13, f[8] = 21, f[9] = 34, f[10] = 55.

  3. Le tableau final est [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55] et F10=55F_{10} = 55.

  4. La boucle passe par i=2,3,…,10i = 2, 3, \ldots, 10, soit 9 additions.

F10=55F_{10} = 55, obtenu avec 9 additions seulement. La version récursive naïve ferait 177 appels pour la même valeur.

Exercice 2 Rendre la monnaie avec les pièces 1, 3 et 4

★★☆Environ 12 min

Les pièces ont pour valeurs 1, 3 et 4 centimes, en quantité illimitée. On note m(s)m(s) le nombre minimal de pièces pour rendre ss centimes.

  1. Écris la relation de récurrence de m(s)m(s).
  2. Calcule m(1)m(1) à m(7)m(7).
  3. Donne le nombre minimal de pièces pour rendre 7 centimes.
Indice 1

Une dernière pièce de valeur xx laisse s−xs - x à rendre.

Indice 2

Garde en mémoire m(0)=0m(0) = 0 pour la case de départ.

Voir la correction pas à pas
  1. Relation : m(0)=0m(0) = 0 et m(s)=min⁡x≤s(1+m(s−x))m(s) = \min_{x \leq s}(1 + m(s - x)) avec x∈{1,3,4}x \in \{1, 3, 4\}.

  2. m(1)=1m(1) = 1 ; m(2)=2m(2) = 2 ; m(3)=min⁡(1+2, 1+0)=1m(3) = \min(1 + 2,\ 1 + 0) = 1 ; m(4)=min⁡(1+1, 1+1, 1+0)=1m(4) = \min(1 + 1,\ 1 + 1,\ 1 + 0) = 1.

  3. m(5)=min⁡(1+m(4), 1+m(2), 1+m(1))=min⁡(2,3,2)=2m(5) = \min(1 + m(4),\ 1 + m(2),\ 1 + m(1)) = \min(2, 3, 2) = 2 ; m(6)=min⁡(1+m(5), 1+m(3), 1+m(2))=min⁡(3,2,3)=2m(6) = \min(1 + m(5),\ 1 + m(3),\ 1 + m(2)) = \min(3, 2, 3) = 2.

  4. m(7)=min⁡(1+m(6), 1+m(4), 1+m(3))=min⁡(3,2,2)=2m(7) = \min(1 + m(6),\ 1 + m(4),\ 1 + m(3)) = \min(3, 2, 2) = 2.

  5. Deux pièces suffisent : 3+4=73 + 4 = 7.

Rendre 7 centimes demande au minimum 2 pièces (une de 3 et une de 4). Le glouton aurait pris 4 puis 3 ici, mais il se trompe sur 6 : la récurrence, elle, ne se trompe jamais.

Exercice 3 Compter les chemins dans une grille

★★★Environ 15 min

Une grille compte 4 lignes et 5 colonnes de cases. On part de la case en haut à gauche et on veut atteindre la case en bas à droite, en se déplaçant seulement d'une case vers la droite ou d'une case vers le bas. On note N(i,j)N(i, j) le nombre de chemins menant du départ à la case de la ligne ii et de la colonne jj (les lignes et colonnes sont numérotées à partir de 0).

  1. Donne N(0,j)N(0, j) et N(i,0)N(i, 0).
  2. Écris la relation de récurrence pour i≥1i \geq 1 et j≥1j \geq 1.
  3. Calcule le nombre de chemins vers la case d'arrivée.
Indice 1

On arrive dans une case par la gauche ou par le haut.

Indice 2

Remplis le tableau ligne par ligne.

Voir la correction pas à pas
  1. Première ligne et première colonne : un seul chemin possible, donc N(0,j)=1N(0, j) = 1 et N(i,0)=1N(i, 0) = 1.

  2. Pour i,j≥1i, j \geq 1 : une case est atteinte depuis la case de gauche ou celle du haut, donc N(i,j)=N(i−1,j)+N(i,j−1)N(i, j) = N(i-1, j) + N(i, j-1).

  3. Ligne 1 : 1, 2, 3, 4, 5. Ligne 2 : 1, 3, 6, 10, 15.

  4. Ligne 3 : 1, 4, 10, 20, 35.

  5. La case d'arrivée est N(3,4)=35N(3, 4) = 35.

Il y a 35 chemins. On retrouve le même type de calcul que pour Fibonacci : une case est la somme de deux cases déjà remplies, ce qui évite de compter les chemins un par un.

Quiz

7 questions · correction immédiate · ton score reste sur ton appareil.

  1. Quelle idée est au cœur de la programmation dynamique ?

  2. Combien d'appels déclenche la fonction récursive naïve fib(5), appel initial compris ?

  3. Dans quel cas la méthode diviser pour régner devient-elle inefficace ?

  4. La méthode ascendante calcule d'abord les cas de base, puis les sous-problèmes de plus en plus grands.

  5. Avec les pièces 1, 3 et 4, quel est le nombre minimal de pièces pour rendre 6 ?

  6. Dans le sac à dos, pourquoi écrit-on V(i−1,c−wi)V(i-1, c - w_i) et non V(i,c−wi)V(i, c - w_i) quand on prend l'objet ii ?

  7. Quelles affirmations sont vraies sur la mémoïsation ?

    Plusieurs réponses possibles.

Les questions qu'on se pose

Quelle est la différence entre mémoïsation et programmation dynamique ?

Les deux techniques sont très proches et reposent sur la même idée : ne pas refaire un calcul déjà fait 5. La mémoïsation désigne surtout l'ajout d'une mémoire à une fonction récursive (méthode descendante). La programmation dynamique, au sens large, regroupe cette approche et l'approche ascendante par tableau, dans laquelle on remplit les cases des plus petits sous-problèmes aux plus grands 6.

Comment savoir si un problème se résout par programmation dynamique ?

Pose-toi trois questions. La réponse se construit-elle à partir de réponses à des problèmes plus petits ? Y a-t-il un optimum à trouver 6 ? Les mêmes sous-problèmes réapparaissent-ils ? Si oui à tout, essaie d'écrire la relation de récurrence. Si tu n'y arrives pas, la méthode ne convient probablement pas.

Pourquoi le glouton ne suffit-il pas pour rendre la monnaie ?

Le glouton prend la plus grosse pièce possible à chaque étape et ne revient jamais sur son choix. Avec les pièces 1, 3 et 4, il rend 6 avec trois pièces (4+1+14 + 1 + 1) alors que deux suffisent (3+33 + 3). La programmation dynamique compare tous les choix possibles de dernière pièce et garde le meilleur.

Que faut-il savoir faire sur ce chapitre ?

La programmation dynamique fait partie de l'algorithmique du programme de terminale NSI 2. Attention : les notes de service qui encadrent l'épreuve écrite ont exclu certaines notions de l'évaluation, dont celle-ci ; vérifie la note en vigueur avec ton professeur. Sache quand même identifier les sous-problèmes, écrire une relation de récurrence, remplir un petit tableau à la main et compléter un programme Python en méthode descendante ou ascendante.

Pourquoi le mot « programmation » dans « programmation dynamique » ?

C'est Richard Bellman qui a lancé cette méthode dans les années 1950 6. Chez lui, « programmation » renvoyait à l'idée de planifier et d'organiser des opérations dans le temps, et non à l'écriture de code 6. Le nom est donc un héritage de ce vocabulaire ancien, même si l'on finit par écrire un programme pour appliquer la méthode.

Sources

Programme visé : Programme de l'enseignement de spécialité de numérique et sciences informatiques de la classe terminale de la voie générale · Bulletin officiel de l'Éducation nationale

  1. Programme de l'enseignement de spécialité de numérique et sciences informatiques de la classe terminale de la voie générale, Bulletin officiel de l'Éducation nationale. Consulté le 7 novembre 2026.
  2. Ressource Éduscol - Programmation dynamique (Terminale NSI), eduscol.education.gouv.fr. Consulté le 7 novembre 2026.
  3. Programmes et ressources en numérique et sciences informatiques - voie générale, eduscol.education.gouv.fr. Consulté le 7 novembre 2026.
  4. Recherche Opérationnelle - Programmation Dynamique, CNRS (Université Lyon). Consulté le 7 novembre 2026.
  5. Programmation dynamique et mémoïsation, CNRS. Consulté le 7 novembre 2026.
  6. Programmation dynamique, Wikipédia. Consulté le 7 novembre 2026.

Les numéros dans le texte renvoient à ces sources. Une source qui ne dit pas ce qu'on lui fait dire ? Signale-le.

Signaler une erreur sur cette page

Je suis en…

Primaire

  • CP Bientôt
  • CE1 Bientôt
  • CE2 Bientôt
  • CM1 Bientôt
  • CM2 Bientôt

Collège

Lycée

Supérieur

  • BTS Bientôt
  • BUT Bientôt
  • Licence Bientôt
  • Prépas Bientôt

Sur cette page