Vous êtes sur la page 1sur 14

Programmation dynamique

Université Ferhat Abbas Sétif


Faculté des Sciences
Computer science département
Algorithmique Avancée et complexité
Prof: Allaoua Refoufi
Semestre1 2020/2021
Cours AAC04
Contenu des cours 04 et 05

 CoursAAC04
 Introduction
 Exemple1: la suite de Fibonacci
 Exemple2 :multiplication d’une chaine de matrices
 CoursAAC05
 Exemple3: La plus longue chaine palindromique
 Exemple4 : le problème du sac à dos (knapsack problem)
 Exemple5 : plus court chemin dans les graphes
Programmation dynamique

« those who can’t remember the past are condemned to repeat it »


« Dynamic programming amounts to breaking down an optimization problem into
simpler sub-problems and storing the solution to each sub-problem so that each sub-
problem is only solved once » R.Bellman
Le principe général de la programmation dynamique selon Bellman :
« Toute sous politique d’une politique optimale est optimale »
Appliquée au domaine des graphes cela donne ;
« tout sous chemin d’un chemin optimal est optimal »
Principes généraux de la P.D.

C’est une méthode générale pour résoudre des problèmes complexes


en les divisant en sous problèmes plus simples.
Etapes de la PD
1. Définir les sous problèmes
2. Obtenir la relation de récurrence à partir d’un sous problème
3. Reconnaitre et résoudre les cas basiques
4. Sauvegarder les résultats intermédiaires(mémoïsation)
5. Généraliser la solution au problème initial
Exemple 1: enter Fibonacci
La suite de Fibonacci est définie par :
F0= F1=1
Fn=Fn-2 + Fn-1
Qui donne la suite : 1,1,2,3,5,8,13,21,etc. On prévoit une croissance
exponentielle. Un algorithme naïf serait par exemple :
fibo1(n):
If n < 2 return 1 else return fibo1(n-2)+fibo1(n-1)
La complexité de cet algorithme serait donc donnée par la relation de
récurrence T(n)=T(n-2)+T(n-1)+(1);T(0)=T(1)=1
On peut dire que T(n-1) ≥ T(n-2);donc T(n) ≥ 2T(n-2) et la solution
donnerait T(n) = (2𝑛/2 ) 𝑐𝑒 𝑞𝑢𝑖 𝑒𝑠𝑡 𝑒𝑛𝑜𝑟𝑚𝑒.
Le problème de cette explosion combinatoire vient du fait que les
résultats intermédiaires sont recalculés un bon nombre de fois, ce qui
alourdit l’algorithme. Comme illustré par l’arbre suivant pendant
l’exécution de F7
Arbre d’exécution de F7

F7

F5 F6

F3 F4 F4 F5

F1 F2 F2 F3
Les nœuds en rouge sont des résultats déjà connus

F0 F1
En mémorisant les résultats partiels on évite les redondances, au lieu de recalculer
on mémorise. Ce qui va diminuer drastiquement le temps d’exécution.
D’où un algorithme plus efficace : on utilise un cache pour stocker les résultats
partiels.
fibo_cache={}
fibo2(n):
if n in fibo_cache{} return fibo_cache[n]
if n < 2 then value = 1 else value = fibo2(n-2)+fibo2(n-1)
fibo_cache[n]=value
return value
Il est maintenant aisé de voir que le temps d’exécution est
proportionnel à n; T(n)=(n), car pour chaque n, Fn est calculé une
seule fois.
En général, en programmation dynamique, la complexité du problème
initial est égale à la complexité d’un sous problème fois le nombre de
sous problèmes.
Exercice : exécuter les deux algorithmes fibo1 et fibo2 pour des
valeurs de n allant de 20 à 100 et estimer le temps d’exécution en
utilisant la commande time de Python.
Exemple2: multiplication d’une chaine de matrices
Problème : soit une chaine A1xA2xA3x…xAn où les Ai sont des matrices. On voudrait
déterminer un ordre optimal, en nombre d’opérations, pour effectuer cette
multiplication.
Exemple soit le produit M =M1xM2xM3xM4 où les dimensions des matrices sont,
respectivement,(10,20),(20,50),(50,1),(1,100)
Si on évalue le produit M dans l’ordre : M1x(M2x(M3xM4)), le nombre d’opérations
serait 5000+20x50x100+10x20x100=125000 opérations.
Si on évalue le produit M selon l’ordre (M1x(M2xM3))xM4), le nombre d’opérations
serait 20x50+10x20+10x100=2200 opérations.
Cet exemple prouve qu’on gagnerait en nombre d’opérations si on arrive à identifier
l’ordre optimal d’évaluation des sous produits.
La première tâche, en PD, consiste à identifier les sous problèmes qui nous
mèneraient vers la solution générale. Ces sous problèmes ne sont autres
que AixAi+1x….xAj pour 1  i  j  n c’est-à-dire une sous chaine de la
chaine matricielle.
Posons C(i,j)=le nombre d’opérations minimal pour effectuer le produit
AixAi+1x….xAj
La taille de ces sous problèmes est |j-i| donc (n2)
La seconde tâche serait de « deviner » la dernière opération qu’on a
effectuée sur le produit AixAi+1x….xAj
C’est surement pour un certain k tel que (AixAi+1x….xAk)x(Ak+1….xAj)
(AixAi+1x….xAk)x(Ak+1….xAj)
En supposons que chaque matrice Ai est de dimension (mi-1,mi), la dernière
opération serait de l’ordre de mi-1xmkxmj car la dimension de la matrice
(AixAi+1x….xAk) est (mi-1,mk) et celle de (Ak+1….xAj) est (mk, mj).
On peut donc généraliser en disant que C(i,i)=0 et :
C(i,j)=min{C(i,k)+C(k+1,j) + mi-1xmkxmj } pour i  k < j
En effet :
 C(i,k) est le nombre d’opérations pour effectuer le produit P1:
(AixAi+1x….xAk)
 C(k+1,j) est le nombre d’opérations pour effectuer le produit P2:
(Ak+1….xAj),
 mi-1xmkxmj est le nombre d’opérations qu’on exécute pour enfin avoir
P1xP2
Voila notre récurrence qu’on va utiliser pour la solution du problème initial, il suffit
d’évaluer C(1,n). Chaque fois qu’on détermine k dans cet algorithme, c’est l’endroit
où on place les parenthèses pour effectuer un produit partiel.
La complexité de cet algorithme est égale au nombre de sous problèmes par le
nombre d’opérations que prend chaque sous problème, donc T(n)=(n2)x(n)=(n3)

Exercice
Poursuivre la solution du problème donné en exemple sur le produit M =M1xM2xM3xM4 où les
dimensions des matrices sont, respectivement,(10,20),(20,50),(50,1),(1,100)
Déterminer l’ordre optimal d’évaluation de ce produit. Il s’agit de remplir la matrice C(i,j) pour en
tirer C(1,4)

Vous aimerez peut-être aussi