Programmation Dynamique
Programmation Dynamique
Programmation Dynamique
Hicham EL YAHYAOUY
CPGE Tanger
Lycee Moulay EL-Hassan
[email protected]
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Plan
1 Introduction
2 Principe générale
Programmation dynamique 1 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Introduction
C’est une des plus vieilles techniques pour produire des algorithmes exacts, plus efficaces que
l’énumération exhaustive.
Principe (Bellman, 1949)
Composer une solution optimale du problème en combinant les solutions (optimales) de ses
sous-problèmes.
Décomposer le problème en des sous-problèmes plus petits ;
Calculer les solutions optimales de tous ces sous-problèmes et les garder en mémoire.
Calculer la solution optimale à partir des solutions optimales des sous-problèmes.
Programmation dynamique 2 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Introduction
Le problème est que dans certaines situations, les sous-problèmes ne sont pas indépendants. On
peut alors retrouver un même sous-problème dans des appels récursifs différents.
Et donc être amené à le résoudre plusieurs fois car dans cette approche dès qu’un sous-problème est
rencontré il est résolu.
Programmation dynamique 3 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Introduction
Le problème est que dans certaines situations, les sous-problèmes ne sont pas indépendants. On
peut alors retrouver un même sous-problème dans des appels récursifs différents.
Et donc être amené à le résoudre plusieurs fois car dans cette approche dès qu’un sous-problème est
rencontré il est résolu.
Exemple : Rappelons la formule de récurrence définissant la suite de Fibonacci :
0 si n = 0
un = 1 si n = 1
un−1 + un−2 si n ≥ 2
Programmation dynamique 3 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Introduction
pour n=5 :
Programmation dynamique 4 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Introduction
pour n=5 :
Programmation dynamique 5 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Principe générale
Remarque 1
On peut alors constater que plusieurs appels sont réalisés avec une même valeur du paramètre. On fait
par exemple ici 5 appels à la fonction avec un paramètre égal à 2.
Programmation dynamique 6 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Principe générale
Remarque 1
On peut alors constater que plusieurs appels sont réalisés avec une même valeur du paramètre. On fait
par exemple ici 5 appels à la fonction avec un paramètre égal à 2.
On réalise ainsi un grand nombre d’opérations inutiles car redondantes. Celles-ci sont très coûteuses et
expliquent la complexité exponentielle de cet algorithme.
Programmation dynamique 6 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Principe générale
Remarque 1
On peut alors constater que plusieurs appels sont réalisés avec une même valeur du paramètre. On fait
par exemple ici 5 appels à la fonction avec un paramètre égal à 2.
On réalise ainsi un grand nombre d’opérations inutiles car redondantes. Celles-ci sont très coûteuses et
expliquent la complexité exponentielle de cet algorithme.
Solution : Pour éviter ces appels récursifs redondants et coûteux, il suffit d’avoir une idée
relativement simple :
On mémorise les résultats des sous-problèmes affin de ne pas les recalculer plusieurs fois.
Cela n’est bien sûr possible que si les sous-problèmes sont dépendants.
Cela signifie donc que ces sous-problèmes ont des sous-sous-problèmes communs.
Programmation dynamique 6 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Pour ce faire, et donc éviter de recalculer plusieurs fois les solutions des mêmes sous-problèmes, on
va mémoriser ces solutions dans une sorte de mémoire cache (liste ou dictionnaire).
Cette technique porte le nom de programmation dynamique, et sa mise en pratique peut prendre
deux formes :
Une forme récursive "Top down" dite de mémoïsation :
On utilise directement la formule de récurrence.
Lors d’un appel récursif, avant d’effectuer un calcul on regarde dans le tableau de mémoire cache si ce
travail n’a pas déjà été effectué.
Programmation dynamique 7 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Pour ce faire, et donc éviter de recalculer plusieurs fois les solutions des mêmes sous-problèmes, on
va mémoriser ces solutions dans une sorte de mémoire cache (liste ou dictionnaire).
Cette technique porte le nom de programmation dynamique, et sa mise en pratique peut prendre
deux formes :
Une forme récursive "Top down" dite de mémoïsation :
On utilise directement la formule de récurrence.
Lors d’un appel récursif, avant d’effectuer un calcul on regarde dans le tableau de mémoire cache si ce
travail n’a pas déjà été effectué.
Une forme itérative "Bottom Up" :
On résout d’abord les sous problèmes de la plus "petite taille", puis ceux de la taille "d’au dessus", etc.
Au fur et à mesure on stocke les résultats obtenus dans le tableau de mémoire cache.
On continue jusqu’à la taille voulue.
Programmation dynamique 7 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Notre mémoire cache sera ici une liste unidimensionnelle. Rappelons que son rôle va être de
mémoriser les résultats des sous-problèmes de tailles inférieures à celui du problème à résoudre.
Pour la suite de Fibonacci, si l’on veut calculer le terme d’indice n, il nous faudra ainsi mémoriser les
termes d’indices 0, 1, ..., n − 1. Cette liste aura donc n + 1 éléments.
Voici la fonction déclarant cette liste, nommée track, et réalisant le premier appel de la fonction
récursive qui effectuera le calcul :
1 def Fibo_DPTD ( n ) :
2 track = [ None ]*( n +1)
3 return Fibo_rec_DPTD (n , track )
Programmation dynamique 8 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Programmation dynamique 9 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Programmation dynamique 9 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Programmation dynamique 10 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Solution Buttom up
Puisqu’elle a le même rôle, il est logique que la mémoire cache soit comme dans le cas Top Down
une liste à n + 1 éléments. La différence est que cette liste ne vas plus se remplir récursivement, en
partant de la valeur n et en décrémentant jusqu’à 0 ou 1, mais itérativement, en partant cette fois de
0 et 1 et en incrémentant jusqu’à n.
Voici la fonction correspondante :
1 def Fibo_DPBU ( n ) :
2 track = [0]*( n +1)
3 track [1] = 1
4 for i in range (2 , n +1) :
5 track [ i ] = track [ i - 1] + track [ i - 2]
6 return track [ n ]
Programmation dynamique 11 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Bottom-up vs Top-down
Programmation dynamique 12 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Programmation dynamique 13 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Problème :
Étant donné deux chaînes de caractères (séquences) x et y, trouver la plus longue sous-séquence
commune (LCS) et afficher sa longueur.
Une sous-séquence est une séquence qui apparaît dans le même ordre relatif, mais pas nécessairement
contigue.
Programmation dynamique 14 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Problème :
Étant donné deux chaînes de caractères (séquences) x et y, trouver la plus longue sous-séquence
commune (LCS) et afficher sa longueur.
Une sous-séquence est une séquence qui apparaît dans le même ordre relatif, mais pas nécessairement
contigue.
Exemple :
x=ABCBDAB
y=BDCABC
"BCAB" est la LCS trouvée dans les deux séquences, la réponse est donc 4.
Programmation dynamique 14 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
cas de base :
Di0 = D0j = 0
Si xi = yj , ils contribuent tous les deux au LCS, donc
Dij = Di−1,j−1 + 1
Programmation dynamique 15 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Solution récursive :
1 def lcs (X , Y , m , n ) :
2 if m == 0 or n == 0:
3 return 0
4 elif X [ m - 1] == Y [ n - 1]:
5 return 1 + lcs (X , Y , m - 1 , n - 1)
6 else :
7 return max ( lcs (X , Y , m , n - 1) , lcs (X , Y , m - 1 , n ) )
Programmation dynamique 16 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Programmation dynamique 17 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Programmation dynamique 19 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Programmation dynamique 20 / 21
Introduction Principe générale Problème : Plus longue sous-chaîne commune (LCS) Programmation Dynamique Vs Glouton vs Diviser pour régner
Programmation dynamique 21 / 21