0% ont trouvé ce document utile (0 vote)
253 vues24 pages

Algorithmique Avancée C2

Transféré par

yassine medjdoub
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
253 vues24 pages

Algorithmique Avancée C2

Transféré par

yassine medjdoub
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Algorithmique 

Avancée
Cours n°2 : Programmation Dynamique

Master 1 – Génie Logiciel
Université Abou­Bakr Belkaïd ­ Tlemcen
2016/2017

Mahfoud Houari
[email protected]
hmahfoud.wordpress.com
Programmation Dynamique
Quelques paradigmes de programmation
Principe de la PRD :
1. C'est un schéma d'algorithmes introduit en 1950 par 
Richard Bellman.
2. Appliquée pour résoudre des problèmes d'optimisation.
3. Basée sur le principe d'optimalité de Bellman :
La solution optimale de quelques problèmes s'appuie 
sur les solutions optimales de leurs sous­problèmes.
4. Chaque sous­problème est résolu une seule fois et sa 
solution optimale est enregistrée.
5. La solution globale est construite, d'une façon ascendante 
ou descendante, en combinant les sous­solutions.
Programmation Dynamique
Quelques paradigmes de programmation
Développement d'un algorithme de PRD :

Caractériser la solution optimale.

Trouver une définition récursive de la solution optimale.

Définir une structure pour enregistrer les sous­solutions.

Résoudre  les  sous­problèmes  d'une  façon  descendante  (Top­
down) ou ascendante (Bottom­up).

Combiner  les  sous­solutions  pour  avoir  une  solution 
optimale du problème initial.
Programmation Dynamique
Quelques paradigmes de programmation
Exemple introductif :
Soit la suite de Fibonacci :
1  si n = 0 ou n = 1
Fn =
 Fn­1 + Fn­2  sinon

Algorithme récursif :
int Fibo(int n){       //Supposons que n ≥ 0.
if (n == 0 || n == 1)
return 1 ;
else 
return Fibo(n ­ 1) + Fibo(n ­ 2) ;
}

Quelle est sa complexité Cn ?
Programmation Dynamique
Quelques paradigmes de programmation
Exemple introductif :
Algorithme récursif :
int Fibo(int n){       //Supposons que n ≥ 0.
if (n == 0 || n == 1)
return 1 ;
else 
return Fibo(n ­ 1) + Fibo(n ­ 2) ;
}

BCET : Cn = C1 = C0 = 1 ⇒ O(1).

WCET : Cn = 1 + Cn­1 + Cn­2  ⇒ O( ???? ).
Programmation Dynamique
Quelques paradigmes de programmation
Exemple introductif :
Arbre des coûts :
Cn

Cn­1 + 1 + Cn­2

Cn­2 + 1 +     Cn­3                                   Cn­3 + 1 +    Cn­4

C2

C1 + 1 +   C0

     
1          1

Coût total : C'est le nombres des appels 
= nombres des nœuds.
Programmation Dynamique
Quelques paradigmes de programmation
Exemple introductif :
Arbre des coûts :
Cn

Cn­1 + 1 + Cn­2

Cn­2 + 1 +     Cn­3                                   Cn­3 + 1 +    Cn­4

C2

C1 + 1 +   C0

     
1          1

Remarque : c'est un ABR de hauteur = n ­ 1.
Programmation Dynamique
Quelques paradigmes de programmation
Exemple introductif :
Arbre des coûts :
Cn

Cn­1 + 1 + Cn­2

Cn­2 + 1 +     Cn­3                                   Cn­3 + 1 +    Cn­4

C2

C1 + 1 +   C0

     
1          1

Remarque : Le nombre de nœuds dans un ABR de 
hauteur h est égal à 2h ­ 1.
Programmation Dynamique
Quelques paradigmes de programmation
Exemple introductif :

Coût total de l'algorithme est ≤  2n­1 – 1 ⇒ O(2n).

Quelles classes de complexité ? ⇒ Exponentielle

Est­il praticable ? ⇒ Il est impraticable

D'où vient cette inefficacité ?
Programmation Dynamique
Quelques paradigmes de programmation
Exemple introductif :
Arbre des coûts :

Fibo(5)

Fibo(4)                                     Fibo(3)

        Fibo(3)             Fibo(2)                       Fibo(2)      Fibo(1)    

Fibo(2)   Fibo(1)    Fibo(1)   Fibo(0)         Fibo(1)    Fibo(0)

D'où vient cette inefficacité ?
⇒ Dû au calcul répétitif des sous­problèmes
Programmation Dynamique
Quelques paradigmes de programmation
Exemple introductif :
D'où l'intuition de calculer une seule fois chaque sous­pb

Algorithme itératif :
int Fibo(int n){       //Supposons que n ≥ 0.
int [] resultats = new int[n + 1] ;
resultats[0] = 1 ;
resultats[1] = 1 ; 
for (int i = 2 ; i ≤ n ; i++){
resultats[i] = resultats[i ­ 1] + resultats[i ­ 2] ;
}
return resultats[n] ;
}
Complexité temporelle : O(n) ⇒ Algorithme linéaire.
Complexité spatiale : O(n).
Programmation Dynamique
Quelques paradigmes de programmation

Application de la PRD pour le problème 
de « Découpe de barres »
Programmation Dynamique
Quelques paradigmes de programmation
Description du problème :
Barre de longueur N

Découpes désirées (de longueur entière):

Découpe (cm) d1 d2 ... dk

Prix (pi) p1 p2 ... pk

Objectif :
Déterminer les découpes à réaliser afin de maximiser le 
revenu total RN.
Programmation Dynamique
Quelques paradigmes de programmation
Instance du problème :
Barre de longueur 4

Découpes désirées :
Longueur 1 2 3 4 5 6 7 8 9 10
Prix (pi) 1 5 8 9 10 17 17 20 24 30

Découpes possibles :

  9                             1+8                            5+5                            8+1

  1+1+5                        1+5+1                    5+1+1                      1+1+1+1
Programmation Dynamique
Quelques paradigmes de programmation
Description récursive de la solution :
RN =max 1 ≤i ≤ N ( pi + RN − i )

Algorithme naïf (k ≤ N):
int CoupeBarre(int n, int[] T, int[] P, int k){
int R = 0 ;
for (int i = 0 ; i < k ; i++){
if(T[i] ≤ n){
R = max(R, P[i] + CoupeBarre(n ­ T[i], T, P, k)) ;
}
}
return R ;
}

Quelle  est  sa  complexité  temporelle  en  fonction  des 


appels récurfis ?
Programmation Dynamique
Quelques paradigmes de programmation
Revenons ici pour calculer la complexité :
Barre de longueur 4

Découpes désirées :
Longueur 1 2 3 4 5 6 7 8 9 10
Prix (pi) 1 5 8 9 10 17 17 20 24 30

Arbre des appels récursifs (pour N=4) :
4

3 2 1 0    

 2      1    0  1      0 0

 1      0    0 0

0 C(N) = C(0) + C(1) +….+ C(N­1)
C(0) = C(1) = 1.
Programmation Dynamique
Quelques paradigmes de programmation
Revenons ici pour calculer la complexité :
Barre de longueur 4

Découpes désirées :
Longueur 1 2 3 4 5 6 7 8 9 10
Prix (pi) 1 5 8 9 10 17 17 20 24 30

Arbre des appels récursifs (pour N=4) :
4

3 2 1 0    

 2      1    0  1      0 0

 1      0    0 0

0 Coût total = 1 + (1 – 2N­1)/(1 – 2) = 2N­1.
Programmation Dynamique
Quelques paradigmes de programmation
Description récursive de la solution :
RN =max 1 ≤i ≤ N ( pi + RN − i )

Algorithme naïf (k ≤ N):
int CoupeBarre(int n, int[] T, int[] P, int k){
int R = 0 ;
for (int i = 0 ; i < k ; i++){
if(T[i] ≤ n){
R = max(R, P[i] + CoupeBarre(n ­ T[i], T, P, k)) ;
}
}
return R ;
}

Complexité recherchée est en O(2N­1) ⇒ Exponentielle.
Programmation Dynamique
Quelques paradigmes de programmation
Solution avec la PRD (Top­down) :
Méthode descendante avec mémorisation :
Hashtable<Integer, Integer> Memo = new Hashtable<Integer, Integer>();

int CB_Memo(int n, int[] T, int[] P, int k){
if (Memo.containsKey(n))
      return Memo.get(n) ;
int R = 0 ;
for (int i = 0 ; i < k ; i++){
if(T[i] ≤ n){
R = max(R, P[i] + CB_Memo(n ­ T[i], T, P, k)) ;
}
}
Memo.put(n, R) ;
return R ;
}

Quelle est l'ordre de grondeur de sa complexité (temporelle et spatiale) ?
Programmation Dynamique
Quelques paradigmes de programmation
Solution avec la PRD (Top­down) :
Méthode descendante avec mémorisation :
Hashtable<Integer, Integer> Memo = new Hashtable<Integer, Integer>();

int CB_Memo(int n, int[] T, int[] P, int k){
if (Memo.containsKey(n))
      return Memo.get(n) ;
int R = 0 ;
for (int i = 0 ; i < k ; i++){
if(T[i] ≤ n){
R = max(R, P[i] + CB_Memo(n ­ T[i], T, P, k)) ;
}
}
Memo.put(n, R) ; Complexité spatiale en O(N).
return R ;
} Complexité temporelle en O(N²).
Programmation Dynamique
Quelques paradigmes de programmation
Remarque importante :

Lorsque vous décidez d'utiliser une structure 
de données (ex. Hashtable) pensez à la 
complexité des méthodes de cette structure 
que vous allez utiliser (ex. put, get, containsKey)
Programmation Dynamique
Quelques paradigmes de programmation
Solution avec la PRD (Top­down) :

Exercice :

Modifiez l'algorithme pour qu'il retourne aussi la 
solution optimale et pas uniquement la valeur 
optimale 
Programmation Dynamique
Quelques paradigmes de programmation
Remarque importante :

La PRD permet généralement de réduire une 
complexité exponentielle à l'aide d'une 
complexité spatiale
Programmation Dynamique
Quelques paradigmes de programmation
Critères d'applicabilité de la PRD :
Sous­solutions optimales :
La  solution  optimale  du  problème  doit  être  basée  sur  des 
sous­solutions optimales.

1. Problème du plus court chemin non­pondéré (Critère vérifié)
2.  Problème du plus long chemin non­pondéré (Critère non­vérifié)

Chevauchement des sous­problèmes :
Deux  sous­problèmes  se  chevauchent  s'il  s'agit  du  même 
sous­problème  qui  apparaît  au  dessous  de  deux  problèmes 
différents (ex. C(2) est un sous­problème de C(4) et C(3)).

Aspect de mémorisation.

Vous aimerez peut-être aussi