La programation dynamique François Lemieux UQAC François Lemieux (UQAC) La programation dynamique 1 / 51
La programmation dynamique 1 Le compromis espace/temps 2 Principes de la programmation dynamique 3 Exemple 1: Calcul des nombres de Fibonacci 4 Exemple 2: Concaténation de nombres premiers 5 Exemple 3: Multiplication chaînée de matrices 6 Exemple 4: Plus court chemin dans un graphe (Floyd) 7 Exemple 5: Sous-chaîne commune de longueur maximale 8 Exemple 6: Disposer des mots en paragraphe François Lemieux (UQAC) La programation dynamique 2 / 51
Le compromis espace-temps Une situation récurrente en informatique est que la diminution du temps d exécution d un algorithme se fait souvent au prix d une augmentation de l espace mémoire. Exemple: Une fonction f : N N peut être remplacer par une table des valeurs. Similairement, diminuer l utilisation de l espace mémoire peut être fait si on accepte d augmenter le temps d exécution. Exemple. Lecture et écriture dans un fichier compressé. François Lemieux (UQAC) La programation dynamique 3 / 51
Principes de la programmation dynamique On évite de refaire certains calculs en les mémorisant dans une table. Cette méthode est souvent utilisée lorsque l on ne peut pas utiliser un algorithme diviser-pour régner pour une des raisons suivantes: 1 Un algorithme diviser-pour-régner se révèle inefficace parce qu il refait souvent les mêmes appels récursifs 2 Un algorithme diviser-pour-régner serait efficace si seulement on pouvait deviner comment diviser le problème Nous allons voir deux exemples qui illustrent ces situations. François Lemieux (UQAC) La programation dynamique 4 / 51
Exemple 1: Nombres de Fibonacci Algorithme diviser-pour-régner (approche descendante): fib1(n) si (n<2) retourner n sinon retourner fib1(n-1) + fib1(n-2) Le temps est Θ(φ n ) où φ = 1+ 5 2 Comme il n y a que n paramètres possibles, alors il y a une multitude d appels identiques. François Lemieux (UQAC) La programation dynamique 5 / 51
fib(5) fib(3) fib(4) fib(1) fib(2) fib(2) fib(3) fib(0) fib(1) fib(0) fib(1) fib(1) fib(2) fib(0) fib(1) François Lemieux (UQAC) La programation dynamique 6 / 51
Meilleure solution On utilise une table T [1 n] initialisé à 0 Après le premier appel à fib(k) on met le résultat dans T [k] Avant chaque appel à fib(k) on regarde dans T [k] pour voir si le résultat a déjà été calculé. François Lemieux (UQAC) La programation dynamique 7 / 51
Approche descendante (fonctions à mémoire) L approche descendante est la façon récursive d implémenter un algorithme de programmation dynamique. Une fonction récursive qui utilise une table pour éviter de répéter des calculs est appelée fonction à mémoire. fib2(n) si T[n]>0 alors retourner T[n] si n<2 alors T[n]=n sinon T[n] = fib2(n-1) + fib2(n-2) retourner T[n] Le temps est Θ(n) François Lemieux (UQAC) La programation dynamique 8 / 51
fib(5) fib(3) fib(4) fib(1) fib(2) fib(2) fib(3) fib(0) fib(1) fib(0) fib(1) fib(1) fib(2) fib(0) fib(1) Les sous-arbres en rouges correspondent à des calculs qui ont déjà été effectués. François Lemieux (UQAC) La programation dynamique 9 / 51
fib(5) fib(3) fib(4) fib(1) fib(2) fib(2) fib(3) fib(0) fib(1) Les noeuds internes correspondent à des appels récursifs distincts, ce qui garantie un temps linéaire. François Lemieux (UQAC) La programation dynamique 10 / 51
Approche ascendante Il s agit d une méthode itérative où on remplit la table de façon ascendante: On commence par les entrées correspondant aux sous-problèmes de petite taille. fib2(n) T[0]=0 T[1]=1 pour i=2 à n faire T[i] = T[i-1] + T[i-2] Le temps est Θ(n) Remarque: Dans ce cas ci, le tableau peut être remplacé par deux variables entières. François Lemieux (UQAC) La programation dynamique 11 / 51
Exemple 2: Concaténation de nombres premiers Supposons que nous disposions d un algorithme Premier(w) permettant de déterminer si une séquence de bits w représente un nombre premier: { 1 si w est premier Premier(w) = 0 sinon François Lemieux (UQAC) La programation dynamique 12 / 51
Description du problème Entrée: Une séquence de n bits w = b 1 b 2 b n Sortie: Vrai si on peut écrire w sous la forme w = w 1 w 2 w m (m > 0) tel que w i est l encodage binaire d un nombre premier, faux sinon. Exemple: La séquence w = 1110110 est la concaténation de 11 (3), 101 (5) et 10 (2). Remarquez que cette solution n est pas unique puisqu on peut aussi décomposer w en 11101 (29) et 10 (2). François Lemieux (UQAC) La programation dynamique 13 / 51
Approche diviser-pour-régner Sequence(w) Si (Premier(w)=1) alors retourner vrai Si (n=1) retourner faux Trouver une décomposition w=uv Si Sequence(u)=vrai et Sequence(v)=vrai alors retourner vrai Sinon retourner faux Si on pouvait trouver efficacement une telle décomposition alors l algorithme Sequence serait aussi efficace. François Lemieux (UQAC) La programation dynamique 14 / 51
Remarque Une idée serait de choisir u comme le plus petit préfixe de w tel que Premier(u) = 1. Si un tel préfixe n existe pas alors on retourne faux. Malheureusement, cette idée ne fonctionne pas. Exemple: Si w = 10110001 alors 10 (2) est le plus petit préfixe de w qui soit premier. Cependant, la seule décomposition possible de w est 101 (5) et 10001 (17). François Lemieux (UQAC) La programation dynamique 15 / 51
Essayer toutes les décompositions possibles Sequence(w) Si (Premier(w)=1) alors retourner vrai Si (n=1) retourner faux Pour i=1 à n-1 faire u = i premiers bits de w v = (n-i) derniers bits de w Si Sequence(u)=vrai et Sequence(v)=vrai alors retourner vrai Retourner faux n 1 T (n) = [T (i) + T (n i)] + Θ(1) i=1 François Lemieux (UQAC) La programation dynamique 16 / 51
On a donc que et on conclu que T (n) = n 1 i=1 [T (i) + T (n i)] + Θ(1) = 2 n 1 i=1 T (i) + Θ(1) > 2T (n 1) T (n) > 2 n T (0) T (n) Ω(2 n ) François Lemieux (UQAC) La programation dynamique 17 / 51
Fonction à mémoire On utilise un tableau T dont chaque case peut être vide ou contenir vrai ou faux. Initialement toutes les cases de T sont vides. Les indices de ce tableau sont les segments de w (c est-à-dire les séquences de la formes b i b j pour i j) On met dans ce tableau le résultats des appels récursifs. François Lemieux (UQAC) La programation dynamique 18 / 51
Sequence(w) Si (T(w) est non vide) alors retourner T(w) T(w)=faux Si (Premier(w)=1) alors T(w)=vrai Si (n=1) alors T(w)=faux Pour i=1 à n-1 faire u = i premiers bits de w v = (n-i) derniers bits de w Si Sequence(u)=vrai et Sequence(v)=vrai alors T(w)=vrai Retourner T(w) François Lemieux (UQAC) La programation dynamique 19 / 51
abcde a bcde ab cde abc de abcd e b cde bc de bcd e c de cd e d e c d Développement partiel de l arbre d exécution pour w = abcde François Lemieux (UQAC) La programation dynamique 20 / 51
Analyse Il y a Θ(n 2 ) segments distincts. L arbre d exécution contient donc Θ(n 2 ) noeuds internes. Chaque noeud interne possède moins de 2n enfants. Le nombre de feuilles est donc O(n 3 ) T (n) O(n 3 ). François Lemieux (UQAC) La programation dynamique 21 / 51
Implémentation du tableau Entrée: w = b 1 b 2 b n On utilise un tableau T n n initialisé de la façon suivante: { vrai si Premier(bi b T [i, j] = j ) = 1 faux sinon Si on dénote par S l ensemble des séquences de bits qui sont des concaténations de nombres premiers alors, à la fin de l algorithme, le tableau sera: { vrai si bi b T [i, j] = j S faux sinon Temps pour l initialisation: Θ(tn 2 ) où t est le temps d exécution de l algorithme Premier. François Lemieux (UQAC) La programation dynamique 22 / 51
Programmation dynamique Sequence(w) pour longueur=2 à n faire pour debut=1 à n-longueur+1 faire fin = debut+longueur-1 pour coupure=debut à fin-1 faire si T[debut,coupure]=vrai et T[coupure+1,fin]=vrai alors T[debut,fin]=vrai Retourner T[1,n] T (n) Θ(n 3 ) François Lemieux (UQAC) La programation dynamique 23 / 51
Exemple Si w = 10101, alors T sera initialisé de la façon suivante: 1 2 3 4 5 1 F V V F F 2 - F F V V 3 - - F V V 4 - - - F F 5 - - - - F Les séquences de longueur 1 correspondent aux entrées de la diagonale principale, les séquences de longueur 2 correspondent aux entrées de la seconde diagonale, etc. François Lemieux (UQAC) La programation dynamique 24 / 51
Exemple (suite) À la fin de l algorithme le tableau sera: 1 2 3 4 5 1 F V V V V 2 - F F V V 3 - - F V V 4 - - - F F 5 - - - - F Remarque: La valeur d une entrée ne dépend que des entrées précédentes sur la même ligne et des entrées suivante sur la même colonne. Par exemple, on met vrai dans T [1, 4] car T [1, 2] et T [3, 4] sont tous les deux vrais. François Lemieux (UQAC) La programation dynamique 25 / 51
Exemple 3: Multiplication chaînée de matrices On veut calculer le produit matriciel: M = M 1 M 2 M n Fait: Multiplier une matrice p q par une matrice q r en utilisant la méthode standard nécessite pqr produits scalaires. Exemple: On veut calculer ABCD. A : 13 5 B : 5 89 C : 89 3 D : 3 34 François Lemieux (UQAC) La programation dynamique 26 / 51
Le nombre de produits scalaires est donné dans le tableau suivant: ((AB)C)D 10582 (AB)(CD) 54201 (A(BC))D 2856 A((BC)D) 4055 A(B(CD)) 26418 Question: Comment trouver la meilleure parenthétisation? François Lemieux (UQAC) La programation dynamique 27 / 51
Essayer toutes les possibilités Soit T (n) le nombre de façons de parenthétiser M 1 M 2 M n M = (M 1 M i ) }{{} T (i) façons (M i+1 M n ) }{{} T (n i) façons T (n) = n 1 i=1 T (i)t (n i) (nombre de Catalan) T (2) = 1, T (3) = 2, T (4) = 5, T (5) = 14, T (10) = 4862, T (15) = 2674440 Fait: T (n) Ω(4 n /n 2 ) François Lemieux (UQAC) La programation dynamique 28 / 51
Solution par programmation dynamique Soit M i : matrice de dimension d i 1 d i Soit m i,j : nombre minimal de produits scalaires nécessaires pour évaluer M i M j Supposons que nous sachions que la meilleure solution implique de placer des parenthèses de la façon suivante: (M i M k )(M k+1 M j ) François Lemieux (UQAC) La programation dynamique 29 / 51
1 M i M k est une matrice d i 1 d k et nécessite m i,k produits scalaires 2 M k+1 M j est une matrice d k d j et nécessite m k+1,j produits scalaires 3 Le nombre total de produits scalaires est m i,k + m k+1,j + d i 1 d k d j On doit trouver la position k qui minimise m i,j : m i,j = { min {m i,k + m k+1,j + d i 1 d k d j } si i < j i k < j 0 si i = j François Lemieux (UQAC) La programation dynamique 30 / 51
Exemple Par exemple, pour calculer X = m 2,5 nous avons besoin de connaître A : (m 2,2 et m 3,5 ), B : (m 2,3 et m 4,5 ) et C : (m 2,4 et m 5,5 ) 1 1 2 3 4 5 6 2 3 4 5 6 A B C X A B C d=5 d=4 d=3 d=2 d=1 d=0 m 2,5 = min{ m 2,2 + m 3,5 + d 1 d 2 d 5, 5.5emm 2,3 + m 4,5 + d 1 d 3 d 5, 5.5emm 2,4 + m 5,5 + d 1 d 4 d 5 } François Lemieux (UQAC) La programation dynamique 31 / 51
Fait 1: Pour calculer une diagonale, on a seulement besoin de connaître les diagonales précédentes. Fait 2: La diagonale d contient les éléments m i,j tels que d = j i Algorithme: 1 Tous les éléments de la diagonale i = 0 sont mis à 0 2 i = i + 1 3 Calculer toutes les entrées de la diagonale i 4 Si i < n aller à 2. François Lemieux (UQAC) La programation dynamique 32 / 51
Exemple Considérons n = 4 matrices dont les dimensions sont données par: d 0 = 13, d 1 = 5, d 2 = 89, d 3 = 3, d 4 = 34 Calcul de la diagonale d = 1 m 1,2 = 13 5 89 = 5785 m 2,3 = 5 89 3 = 1335 m 3,4 = 89 3 34 = 9078 François Lemieux (UQAC) La programation dynamique 33 / 51
Calcul de la diagonale d = 2 m 1,3 = min{m 1,1 + m 2,3 + 13 5 3, m 1,2 + m 3,3 + 13 89 3} = min{1530, 9256} = 1530 m 2,4 = min{m 2,2 + m 3,4 + 5 89 34, m 2,3 + m 4,4 + 5 3 34} = min{24208, 1845} = 1845 François Lemieux (UQAC) La programation dynamique 34 / 51
Calcul de la diagonale d = 3 m 1,4 = min{m 1,1 + m 2,4 + 13 5 34, m 1,2 + m 3,4 + 13 89 34, m 1,2 + m 4,4 + 13 3 34} = min{4055, 54201, 2856} = 2856 1 2 3 4 1 0 5785 1520 2856 2 0 1335 1845 3 0 9078 4 0 François Lemieux (UQAC) La programation dynamique 35 / 51
Analyse Pour 0 d n 1 il y a n d éléments sur la diagonale d Pour chaque élément, on doit considérer d possibilités. Le temps d exécution est: Donc T (n) θ(n 3 ) T (n) = n 1 (n d)d d=1 = n n 1 d=1 d n 1 d 2 d=1 = n2 (n 1) 2 n(n 1)(2n 1) 6 = n3 n 6 François Lemieux (UQAC) La programation dynamique 36 / 51
Exemple 4: Plus court chemin dans un graphe Entrée: Problème: Un graphe dirigé G = N, A où chaque arc possède une longueur non négative. Trouver la longueur du plus court chemin entre tous les noeuds. On suppose N = {1, 2,..., n} On suppose aussi que G est donné sous forme d une matrice L[1...n, 1...n]. François Lemieux (UQAC) La programation dynamique 37 / 51
Algorithme de Floyd Cet algorithme construit une matrice D qui donne la longueur du plus court chemin entre chaque pair de noeud. Idée: Initialise D à L Après l itération k, D donne la longueur du plus court chemin lorsque l on utilise que les noeuds dans {1, 2,..., k} comme noeuds intermédiaires. Définition: D k est la matrice D après l itération k (D 0 = L). François Lemieux (UQAC) La programation dynamique 38 / 51
D k [i, j] = min {D k 1 [i, j], D k 1 [i, k] + D k 1 [k, j]} i MD k-1 [i,j] j MD k-1 [i,k] k MD k-1 [k,j] François Lemieux (UQAC) La programation dynamique 39 / 51
fonction Floyd(L[1...n,1...n]) D=L pour k=1 à n faire pour i=1 à n faire pour j=1 à n faire D[i,j] = min{d[i,j], D[i,k]+D[k,j]} retourner D Temps dans Θ(n 3 ) François Lemieux (UQAC) La programation dynamique 40 / 51
15 1 4 5 50 30 5 5 15 2 3 15 D 0 = L = 0 5 50 0 15 5 30 0 15 15 5 0 François Lemieux (UQAC) La programation dynamique 41 / 51
D 1 = D 3 = 0 5 50 0 15 5 30 35 0 15 15 20 5 0 0 5 20 10 45 0 15 5 30 35 0 15 15 20 5 0 D 2 = D 4 = 0 5 20 10 50 0 15 5 30 35 0 15 15 20 5 0 0 5 15 10 20 0 10 5 30 35 0 15 15 20 5 0 François Lemieux (UQAC) La programation dynamique 42 / 51
Sous-chaîne commune de longueur maximale Entrée Deux chaînes de caractères x = x 1, x 2 x m et y = y 1 y 2 y n. Problème Trouver une chaîne z = z 1 z 2 z k de longueur maximale telle que z est une sous-chaîne de x et y. Exemple: Si x = abcbdab et y = bdcaba alors bca est une sous-chaîne commune tandis que bcba est une sous-chaîne commune de longueur maximale. François Lemieux (UQAC) La programation dynamique 43 / 51
Définition: MaxCom(x, y) est l ensemble de toutes les sous-chaînes communes de longueur maximale entre x et y. Observation: Soit x = x 1 x m et y = y 1 y n, deux chaînes et soit z = z 1 z k MaxCom(x, y). 1 Si x m = y n alors 1 z k = x m = y n et 2 z 1 z k 1 MaxCom(x 1 x m 1, y 1 y n 1 ) 2 Si x m y m et z k x m alors z MaxCom(x 1 x m 1, y) 3 Si x m y m et z k y n alors z MaxCom(x, y 1 y n 1 ) François Lemieux (UQAC) La programation dynamique 44 / 51
Définition: Soit C i,j la longueur de la sous-chaîne commune de longueur maximale entre x 1 x i et y 1 y j. On a: 0 si i = 0 ou j = 0 C i,j = C i 1,j 1 + 1 si i, j > 0 et x i = y j max{c i.j 1, C i 1,j } si i, j > 0 et x i y j François Lemieux (UQAC) La programation dynamique 45 / 51
SousChaineMax(x 1 x m, y 1 y n ) pour i=1 à m faire C i,0 = 0 pour j=1 à n faire C 0,j = 0 pour i= 1 à m faire pour j=1 à n faire si (x i = y i ) alors C i,j = C i 1,j 1 + 1 sinon si (C i 1,j C i,j 1 ) alors C i,j = C i 1,j sinon C i,j = C i,j 1 François Lemieux (UQAC) La programation dynamique 46 / 51
Disposer des mots en paragraphe On désire séparer une séquence de mots m 1,..., m n en une série de lignes constituant un paragraphe. Notre objectif est d éviter autant que possible la perte d espace à la fin de chaque ligne à l exclusion de la dernière. Pour simplifier, on suppose que chaque mot doit être écrit sur une seule ligne et que tous les caractères (incluant les caractères d espacement) ont la même largeur. François Lemieux (UQAC) La programation dynamique 47 / 51
Disposer des mots en paragraphe L entrée est composée de n entiers w 1, w 2,... w n représentant le nombre de caractères dans chaque mot ainsi que d un entier L représentant la largeur du paragraphe. Pour simplifier les calculs, on suppose que les mots se terminent tous par un espace supplémentaire. Par exemple, si m i est le mot ou alors w i = 3. On suppose aussi que L inclu un espace supplémentaire (e.g. pour des lignes de 80 caractères on a L = 81). François Lemieux (UQAC) La programation dynamique 48 / 51
Disposer des mots en paragraphe La principale contrainte est donc que si les mots i à j sont placés sur la même ligne alors on doit avoir w i + w i+1 + + w j L. Dans ce cas la perte d espace est X = L (w i + w i+1 + + w j ) On défini la pénalité d une ligne comme X 3 (on pénalise ainsi d avantage une ligne ayant une grande perte d espace que plusieurs lignes ayant une petite perte d espace). On désire minimiser la pénalité du paragraphe, c est-à-dire la somme des pénalités de chaque ligne. François Lemieux (UQAC) La programation dynamique 49 / 51
Disposer des mots en paragraphe Nous utiliserons deux tableaux de taille n: PEN: FIN: Remarque: Pour chaque indice i, PEN[i] contient la pénalité minimale du paragraphe contenant uniquement les mots w i,..., w n. Pour chaque indice i, FIN[i] contient l indice du dernier mot de la première ligne dans la solution optimal du problème restreint aux mots w i,..., w n. Si FIN[i]=k alors PEN[i]=(L (w i + + w k )) 3 + PEN(k+1) François Lemieux (UQAC) La programation dynamique 50 / 51
Disposer des mots en paragraphe Paragraphe(w i,..., w n, L) Si PEN[i] est non vide alors return PEN[i] Si (w i + + w n L) alors PEN[i]=0 FIN[i]=n return 0 M= kmin=i k=i tantque (w i + + w k L) faire P= Paragraphe(w k+1,..., w n, L) + (L (w i + + w k )) 3 Si (P < M) alors M=P kmin=k k++ FIN[i]=kmin return PEN[i]=M François Lemieux (UQAC) La programation dynamique 51 / 51