Telechargé par pierre.kelbert

Programmation Dynamique

publicité
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+2 5
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(4)
fib(3)
fib(2)
fib(2)
fib(1)
fib(0)
fib(1)
fib(0)
fib(3)
fib(1)
fib(1)
fib(2)
fib(0)
François Lemieux (UQAC)
La programation dynamique
fib(1)
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(4)
fib(3)
fib(2)
fib(2)
fib(1)
fib(0)
fib(1)
fib(0)
fib(3)
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(4)
fib(3)
fib(2)
fib(2)
fib(1)
fib(0)
fib(3)
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 = b1 b2 · · · bn
Sortie: Vrai si on peut écrire w sous la forme w = w1 w2 · · · wm
(m > 0) tel que wi 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
T (n) =
n−1
X
[T (i) + T (n − i)] + Θ(1)
i=1
François Lemieux (UQAC)
La programation dynamique
16 / 51
Pn−1
T (n) =
i=1 [T (i) + T (n − i)] + Θ(1)
P
= 2 n−1
i=1 T (i) + Θ(1)
> 2T (n − 1)
On a donc que
T (n) > 2n T (0)
et on conclu que
T (n) ∈ Ω(2n )
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 bi · · · bj 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
ab
bcde
b
cde
c
de
cd
d
e
c
bc
abc
cde
de
bcd
de
abcd
e
e
e
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 Θ(n2 ) segments distincts.
L’arbre d’exécution contient donc Θ(n2 ) noeuds internes.
Chaque noeud interne possède moins de 2n enfants.
Le nombre de feuilles est donc O(n3 )
T (n) ∈ O(n3 ).
François Lemieux (UQAC)
La programation dynamique
21 / 51
Implémentation du tableau
Entrée: w = b1 b2 · · · bn
On utilise un tableau Tn×n initialisé de la façon suivante:
vrai si Premier(bi · · · bj ) = 1
T [i, j] =
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 · · · bj ∈ S
T [i, j] =
faux
sinon
Temps pour l’initialisation: Θ(tn2 ) 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) ∈ Θ(n3 )
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
-
2
V
F
-
3
V
F
F
-
4
F
V
V
F
-
5
F
V
V
F
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
-
2
V
F
-
3
V
F
F
-
4
V
V
V
F
-
5
V
V
V
F
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 = M1 M2 · · · Mn
Fait: Multiplier une matrice p × q par une matrice q × r en utilisant la
méthode standard nécessite pqr produits scalaires.
Exemple:
A : 13 × 5
B : 5 × 89
C : 89 × 3
D : 3 × 34
On veut calculer ABCD.
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 M1 M2 · · · Mn
M = (M1 · · · Mi ) (Mi+1 · · · Mn )
{z
}
| {z } |
T (i) façons T (n − i) façons
T (n) =
n−1
P
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) ∈ Ω(4n /n2 )
François Lemieux (UQAC)
La programation dynamique
28 / 51
Solution par programmation dynamique
Soit Mi : matrice de dimension di−1 × di
Soit mi,j : nombre minimal de produits scalaires nécessaires pour évaluer
Mi · · · Mj
Supposons que nous sachions que la meilleure solution implique de placer
des parenthèses de la façon suivante:
(Mi · · · Mk )(Mk+1 · · · Mj )
François Lemieux (UQAC)
La programation dynamique
29 / 51
1
Mi · · · Mk est une matrice di−1 × dk et nécessite mi,k produits
scalaires
2
Mk+1 · · · Mj est une matrice dk × dj et nécessite mk+1,j produits
scalaires
3
Le nombre total de produits scalaires est mi,k + mk+1,j + di−1 dk dj
On doit trouver la position k qui minimise mi,j :
mi,j =
(
François Lemieux (UQAC)
min {mi,k + mk+1,j + di−1 dk dj } si i < j
i ≤k <j
0
La programation dynamique
si i = j
30 / 51
Exemple
Par exemple, pour calculer X = m2,5 nous avons besoin de connaı̂tre
A : (m2,2 et m3,5 ), B : (m2,3 et m4,5 ) et C : (m2,4 et m5,5 )
1
2
3
4
5
A
B
C
X
6
1
2
3
A
4
B
5
C
6
d=5
d=4
d=3
d=2
d=1
d=0
m2,5 = min{ m2,2 + m3,5 + d1 d2 d5 ,
m2,3 + m4,5 + d1 d3 d5 ,
m2,4 + m5,5 + d1 d4 d5 }
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 mi,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:
d0 = 13, d1 = 5, d2 = 89, d3 = 3, d4 = 34
Calcul de la diagonale d = 1
m1,2 = 13 × 5 × 89 = 5785
m2,3 = 5 × 89 × 3 = 1335
m3,4 = 89 × 3 × 34 = 9078
François Lemieux (UQAC)
La programation dynamique
33 / 51
Calcul de la diagonale d = 2
m1,3 = min{m1,1 + m2,3 + 13 × 5 × 3,
m1,2 + m3,3 + 13 × 89 × 3}
= min{1530, 9256}
= 1530
m2,4 = min{m2,2 + m3,4 + 5 × 89 × 34,
m2,3 + m4,4 + 5 × 3 × 34}
= min{24208, 1845}
= 1845
François Lemieux (UQAC)
La programation dynamique
34 / 51
Calcul de la diagonale d = 3
m1,4 = min{m1,1 + m2,4 + 13 × 5 × 34,
m1,2 + m3,4 + 13 × 89 × 34,
m1,2 + m4,4 + 13 × 3 × 34}
= min{4055, 54201, 2856}
= 2856
1
2
3
4
François Lemieux (UQAC)
1
0
2
5785
0
3
1530
1335
0
4
2856
1845
9078
0
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:
T (n) =
n−1
P
= n
=
=
(n − d)d
d=1
n−1
P
d−
d=1
n2 (n−1)
2
n3 −n
6
−
n−1
P
d2
d=1
n(n−1)(2n−1)
6
Donc T (n) ∈ θ(n3 )
François Lemieux (UQAC)
La programation dynamique
36 / 51
Exemple 4: Plus court chemin dans un graphe
Entrée: Un graphe dirigé G = hN, Ai où chaque arc possède une
longueur non négative.
Problème: 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: Dk est la matrice D après l’itération k (D0 = L).
François Lemieux (UQAC)
La programation dynamique
38 / 51
Dk [i, j] = min {Dk−1 [i, j], Dk−1 [i, k] + Dk−1 [k, j]}
M
Dk-1[i,j]
i
j
M
Dk-1[i,k]
M
Dk-1[k,j]
k
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 Θ(n3 )
François Lemieux (UQAC)
La programation dynamique
40 / 51
15
4
1
30
5
5
50
5
15
3
2
15


0 5 ∞ ∞
 50 0 15 5 

D0 = L = 
 30 ∞ 0 15 
15 ∞ 5 0
François Lemieux (UQAC)

0
 50
D1 = 
 30
15

0
 45
D3 = 
 30
15
François Lemieux (UQAC)
La programation dynamique
5
0
35
20
41 / 51


∞ ∞
0 5
 50 0
15 5 
 D2 = 
 30 35
0 15 
15 20
5 0


5 20 10
0
 20
0 15 5 
 D4 = 
 30
35 0 15 
20 5 0
15
La programation dynamique
5
0
35
20
20
15
0
5
15
10
0
5

10
5 

15 
0

10
5 

15 
0
42 / 51
Sous-chaı̂ne commune de longueur maximale
Entrée Deux chaı̂nes de caractères x = x1 , x2 · · · xm et
y = y1 y2 · · · yn .
Problème Trouver une chaı̂ne z = z1 z2 · · · zk 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 = x1 · · · xm et y = y1 · · · yn , deux chaı̂nes et soit
z = z1 · · · zk ∈ MaxCom(x, y ).
1
Si xm = yn alors
1
2
2
3
zk = xm = yn et
z1 · · · zk−1 ∈ MaxCom(x1 · · · xm−1 , y1 · · · yn−1 )
Si xm 6= ym et zk 6= xm alors z ∈ MaxCom(x1 · · · xm−1 , y )
Si xm 6= ym et zk 6= yn alors z ∈ MaxCom(x, y1 · · · yn−1 )
François Lemieux (UQAC)
La programation dynamique
44 / 51
Définition: Soit Ci,j la longueur de la sous-chaı̂ne commune de longueur
maximale entre x1 · · · xi et y1 · · · yj .
On a:

si i = 0 ou j = 0
 0
C
+1
si i, j > 0 et xi = yj
Ci,j =
 i−1,j−1
max{Ci.j−1 , Ci−1,j } si i, j > 0 et xi 6= yj
François Lemieux (UQAC)
La programation dynamique
45 / 51
SousChaineMax(x1 · · · xm , y1 · · · yn )
pour i=1 à m faire Ci,0 = 0
pour j=1 à n faire C0,j = 0
pour i= 1 à m faire
pour j=1 à n faire
si (xi = yi ) alors Ci,j = Ci−1,j−1 + 1
sinon si (Ci−1,j ≥ Ci,j−1 ) alors Ci,j = Ci−1,j
sinon Ci,j = Ci,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 m1 , . . . , mn 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 w1 , w2 , . . . wn 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 mi est le mot “ou” alors wi = 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 wi + wi+1 + · · · + wj ≤ L. Dans ce cas la
perte d’espace est
X = L − (wi + wi+1 + · · · + wj )
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: Pour chaque indice i, PEN[i] contient la pénalité minimale
du paragraphe contenant uniquement les mots wi , . . . , wn .
FIN: 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 wi , . . . , wn .
Remarque: Si FIN[i]=k alors
PEN[i]=(L − (wi + · · · + wk ))3 + PEN(k+1)
François Lemieux (UQAC)
La programation dynamique
50 / 51
Disposer des mots en paragraphe
Paragraphe(wi , . . . , wn , L)
Si PEN[i] est non vide alors return PEN[i]
Si (wi + · · · + wn ≤ L) alors
PEN[i]=0
FIN[i]=n
return 0
M=∞
kmin=i
k=i
tantque (wi + · · · + wk ≤ L) faire
P= Paragraphe(wk+1 , . . . , wn , L) + (L − (wi + · · · + wk ))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
Téléchargement