Vous êtes sur la page 1sur 130

Algorithmique

Georges Edouard KOUAMOU


Ecole Nationale Supérieure Polytechnique de Yaoundé
Cours de 3ème Année Génie Informatique
Plan du cours
• Introduction Générale
• Notation asymptotique de la complexité
• Récursivité et approche DPR
• Algorithmes de Tri
• Programmation dynamique
• Algorithmes élémentaires pour les Graphes
• Structures de données usuelles

Cours de 3GI 2
Bibliographie
• D. Beauquier, J. Berstel, Ph. Chretienne. Elements d'algorithmique,
Masson, 2005.
• Thomas Cormen, Charles Leiserson, Ronald Rivest et Clifford Stein.
INTRODUCTION À L’ALGORITHMIQUE, Cours et exercices, Dunod
• Simon Harris and James Ross. Beginning Algorithms, Wiley
Publishing, Inc. 2006
• M. C. Gaudel, M. Soria et C. Froidevaux. Types de Données et
Algorithmes, Vol1. Analyse d’Algorithmes, Définition des Types de
Données, INRIA, Collection Didactique

Cours de 3GI 3
Introduction générale
• Définition des termes (algorithme et algorithmique)
• Définition formelle
• Définition informelle
• L’utilité de ce cours
• Le rôle des algorithmes par rapport aux autres technologies
informatiques

Cours de 3GI 4
Définitions
• Définition informelle du terme algorithme :
• procédure de calcul bien définie qui prend en entrée une valeur, ou un ensemble
de valeurs, et qui donne en sortie une valeur, ou un ensemble de valeurs.
• Un algorithme est donc une séquence d’étapes de calcul qui transforment
l’entrée en sortie.
• un algorithme se défini comme un outil permettant de résoudre un
problème de calcul bien spécifié.
• Algorithmique: ensemble des techniques et règles nécessaires pour
écrire les algorithmes et analyser leur efficacité

Cours de 3GI 5
Exemple
• Le problème de tri
• Définition formelle de ce problème
• Entrée : suite de n nombres (a1, a2, ..., an).
• Sortie : permutation (réorganisation) (a’1, a’2, ..., a’n) de la suite donnée en
entrée, de façon que a’1  a’2  · · ·  a’n.

Cours de 3GI 6
Algorithme correct vs incorrect
• Un algorithme est dit correct si, pour chaque instance en entrée, il se
termine en produisant la bonne sortie
• Un algorithme incorrect risque
• de ne pas se terminer pour certaines instances en entrée
• de se terminer sur une réponse autre que celle désirée.

Cours de 3GI 7
Typologie des algorithmes
• Le problème de tri
• Le projet du génome humain
• d’identifier les 100 000 gènes de l’ADN humain,
• de déterminer les séquences des 3 milliards de paires de bases chimiques qui constituent
l’ADN humain
• Internet permet d’accéder rapidement à toutes sortes de données. Tout cela
repose sur des algorithmes intelligents qui permettent de gérer et manipuler de
grosses masses de données.
• Exemples de problèmes à résoudre : recherche de routes optimales pour l’acheminement des
données
• Calcul matriciel
• Soit une suite A1, A2, . . . , An de n matrices, dont nous voulons calculer le produit A1A2 . . .
An.

Cours de 3GI 8
Structures de données
• Une structures de données est un moyen de stocker et organiser des
données pour faciliter l’accès à ces données et leur modification
• Aucune structure de données ne répond à tous les besoins
• Il est important de connaître les forces et limitations de plusieurs de ces
structures.

Cours de 3GI 9
Technique
• Ce cours vous enseignera des techniques de conception et d’analyse
d’algorithme, de façon que
• vous puissiez créer des algorithmes de votre cru,
• prouver qu’ils fournissent la bonne réponse
• et comprendre leur efficacité.
• Supposez que les ordinateurs soient infiniment rapides et que leurs
mémoires soient gratuites. Faudrait-il encore étudier les algorithmes?

Cours de 3GI 10
Efficacité
• les ordinateurs ne sont pas infiniment rapides. Quelque soit la
fréquence du processeur
• Si bon marché que puisse être la mémoire, elle n’est pas gratuite.
• Conséquence
• Le temps machine est donc une ressource limitée et il en est de même de
l’espace mémoire.
• Il faut utiliser ces ressources avec parcimonie,
• D’où l’intérêt
• des algorithmes performants, en termes de durée et d’encombrement qui vous
aideront à atteindre cet objectif

Cours de 3GI 11
Efficacité
• Soit un ordinateur rapide (ordinateur A) exécutant un algorithme donné en n²
• Supposez que l’ordinateur A exécute un milliard d’instructions par seconde
• Soit un ordinateur lent (ordinateur B) exécutant une version du même algorithme en nlgn
• l’ordinateur B n’exécute que dix millions d’instructions par seconde
• Ces deux machines doivent travailler sur un tableau d’un million de nombres.
• l’ordinateur A est 100 fois plus rapide que l’ordinateur B en termes de puissance de calcul brute.
• Pour rendre la différence encore plus sensible, supposez que le meilleur programmeur du monde
écrive la 1ère version de l’algo en langage machine pour l’ordinateur A et que le code résultant
demande 2n2 instructions pour traiter n nombres. (Ici, c1 = 2.)
• L’autre version, en revanche, est programmée pour l’ordinateur B par un programmeur médiocre
utilisant un langage de haut niveau avec un compilateur peu performant, de sorte que le code
résultant demande 50n lg n instructions (donc,c2 = 50). Pour traiter n nombres
• Faite le calcul ?!!!!!!!! ………

Cours de 3GI 12
Efficacité

T ( A) = 9
( ) 6 2
2. 10 instructions
= 2000 sec ondes
10 instructions / sec ondes
6 6
50.10 lg 10 instructions
T ( B) = 7  100 sec ondes
10 instructions / sec ondes
Avec un algorithme dont le temps d’exécution croît plus
lentement, même si le compilateur est médiocre la machine B
tourne 20 fois plus vite que la machine A

Cours de 3GI 13
Quiz
• Supposez que les ordinateurs soient infiniment rapides et que leurs
mémoires soient gratuites. Faudrait-il encore étudier les algorithmes ?
• On devrait étudier les algorithmes quelque soit la rapidité des
ordinateurs
• ne serait-ce que pour montrer que la solution ne boucle pas
indéfiniment et qu’elle se termine avec la bonne réponse.

Cours de 3GI 14
Algorithmes et autres technologies
• Même si une application n’emploie pas d’algorithmes au niveau de l’application elle-même, elle
s’appuie indirectement sur une foule d’algorithmes.
• L’application s’exécute sur des matériels performants ?
• La conception de ces matériels a utilisé des algorithmes.
• L’application tourne par dessus des interfaces graphiques ?
• Toutes les interfaces utilisateur graphiques reposent sur des algorithmes.
• L’application fonctionne en réseau ?
• Le routage s’appuie fondamentalement sur des algorithmes.
• L’application a été écrite dans un langage autre que du code machine ?
• elle a été traduite par un compilateur, un interpréteur ou un assembleur, toutes ces belles choses
faisant un usage intensif d’algorithmes.
• Les algorithmes sont au cœur de la plupart des technologies employées dans les ordinateurs
modernes.

Cours de 3GI 15
Exercice
• Quelle est la valeur minimale de n (resp la plage de valeurs) pour
laquelle un algorithme dont le temps d’exécution est 100n2 s’exécute
plus vite qu’un algorithme dont le temps d’exécution est 2n sur la
même machine ?

Cours de 3GI 16
Complexité d’un algorithme
Notation asymptotique
Principe de base
• Un algorithme est un ensemble d'opérations de calcul élémentaires,
organise selon des règles précises dans le but de résoudre un
problème donne.
• Les opérations élémentaires sont par exemple
• les opérations arithmétiques usuelles,
• les transferts de données,
• les comparaisons entre données,
• etc.

Cours de 3GI 18
Principe de base
• Ne considérer comme véritablement élémentaires que les opérations
dont le temps de calcul est constant, c'est-à-dire ne dépend pas de la
taille des opérandes.
• L'efficacité en temps d'un algorithme se mesure en fonction d'un
paramètre, généralement la « taille » du problème.
• Ce n'est évidemment pas le temps physique, exprimé en millisecondes ou en
heures qui importe.

Cours de 3GI 19
Exemples d’opérations élémentaires
• Recherche d’1 élément dans une liste
• Nombre de comparaison entre cet éléments et les entrées de la liste
• Recherche d’1 élément sur le disque
• Nombre d’accès à la mémoire secondaire
• Trier une liste d’éléments
• Le nombre de comparaisons entre 2 éléments
• Le nombre de déplacements (permutations)
• Multiplier deux matrices
• Nombre de multiplications arithmétiques
• Nombre d’additions arithmétiques

Cours de 3GI 20
Énoncé du problème
• Considérons un problème donné, et un algorithme pour le résoudre.
• Sur une donnée x de taille n, l'algorithme requiert un certain temps,
mesuré en nombre d'opérations élémentaires, soit c(x).
• Le coût en temps varie évidemment avec la taille de la donnée, mais
peut aussi varier sur les différentes données de même taille n
• Notre but est d'évaluer le coût d'un algorithme, selon certains
critères, et en fonction de la taille n des données.

Cours de 3GI 21
Calcul de la complexité
• Déterminer les opérations fondamentales, ensuite compter le
nombre d’opérations de chaque type
• Pas de règles générales pour ce comptage, mais quelques astuces
1. Séquence d’instruction: leurs nombres s’ajoutent
2. Branchements conditionnels: on ne sait pas a priori quelle branche sera
exécutée
Soit X: if C then I1 else I2 alors P(X) P(C)+ max(P(I1), P(I2))

Cours de 3GI 22
Calcul de la complexité
3. Pour les boucles, i étant l’incrément, P(i) le nombre d’opérations
fondamentales de la ième étape, Coût =  P (i )
i
• Pour les appels de procédures non récursives, ordonner les
procédures de telle manière que chacune n’appelle que des
procédures dont le coût a déjà été évalué
• Pour les appels récursifs, il faut trouver la formule de récurrence.
Pour la factorielle par exemple:

T (n) = T (n − 1) + 1, n  1 et T (1) = 1

Cours de 3GI 23
Notation
• On évalue l'efficacité d'un algorithme en donnant l'ordre de grandeur
du nombre d'opérations qu'il effectue lorsque la taille du problème
qu'il résout augmente.
• On parle ainsi d'algorithme linéaire, quadratique, logarithmique, etc.
• Les notations de Landau sont un moyen commode d'exprimer cet
ordre de grandeur.
• la notation  donne une majoration de l'ordre de grandeur;
• la notation  en donne une minoration,
• la notation  deux bornes sur l'ordre de grandeur.

Cours de 3GI 24
Représentation graphique
c2g(n) cg(n) f(n)

f(n) f(n) cg(n)

c1g(n)

n0 n0 n0
f(n)=(g(n)) f(n)=(g(n)) f(n)=(g(n))

Cours de 3GI 25
Notation 
• On considère une fonction g:→. Etant donnée x0-,+,
• on désigne par O(g) l'ensemble des fonctions f pour lesquelles il
existe un voisinage V de x0 et une constante k > 0 tels que f(x)
kg(x) (x V )
• Exemple. Au voisinage de 0,
• x2  O(x);
• ln(1 + x)  O(x)

Cours de 3GI 26
Notation 
• Pour le cas x0=+, un intervalle est un ouvert ]a ,+[
• Par conséquent f  O(g) au voisinage de + s’il existe 2 nombre k, a>0
tels que f(x) kg(x) pour tout x > a
• Exemple. Au voisinage de l’infini,
• x  O(x2); ln(x) /x O(1); X+1  O(x)

• En effet
( )
P( x) = a 0 x k + a1 x k −1 +  + a k on a P( x)   x k au voisinage de + 
P( x) = a 0 x k + a1 x k −1 +  + a k  ( a 0 + a1 +  + a k )x k

Cours de 3GI 27
Exercices

f = ( g )  f = ( g )

f = ( g )  f = ( g )  f = ( g )

Cours de 3GI 28
La récursivité
Définition
• Technique de définition d’un problème en termes d’une ou de
plusieurs versions du même problème
• La solution au problème initial est construite à partir des résultats des
versions réduites
• Exemple: l’exponentiation

1 if n = 0 *+
a =
n
n −1
où a  
a  a if n  0
Cours de 3GI 30
Caractéristiques
• Éviter les références circulaires
• Les sous problèmes doivent être identiques au problème initial, mais
de taille plus réduite
• Les cas de base ont des solutions connues/directes
• Les solutions aux cas de base sont combinées d’une certaine façon
pour obtenir la solution au problème général

Cours de 3GI 31
Exemple: la factorielle
1 Fonction factorielle(n: in Entier): Entier
2 -- Factorielle de n
3
4 Nécessite : n >= 0
5 Début
6 Si n <= 1 Alors
7 Résultat < 1
8 Sinon
9 Résultat < n * factorielle(n-1)
10 FinSi
12 Fin
• Remarque : factorielle(n-1) est l’appel récursif.

Cours de 3GI 32
Fondement mathématique
• Le corps de la fonction factorielle précédente correspond à la définition
mathématique de la factorielle donnée sous forme de récurrence :
1 n  0,1
n! = 
n  (n − 1)! sinon
• Remarque :
• On pourrait mathématiquement utiliser la notation suivante pour définir la
factorielle n
n! =  i = 1  2    n − 1  n
i =1

• Elle conduirait à un sous-programme non récursif utilisant une boucle Pour.


• Les définitions par récurrence sont souvent plus concises et claires que leur
équivalent itératif.

Cours de 3GI 33
Terminaison
• Danger :
• Il faut s’assurer que les appels récursifs s’arrêtent pour garantir la terminaison de
l’algorithme.
• Règle :
• Un algorithme récursif doit toujours faire apparaître deux éléments :
• le cas de base où l’on sait écrire le code sans nouvel appel récursif;
• le cas général dans lequel on fait des appels récursifs.
• Terminaison : Les appels récursifs doivent porter sur un problème de taille
strictement inférieure, supérieure à la taille du cas de base.
• Attention : Cette condition est suffisante mais pas nécessaire!

Cours de 3GI 34
Récursivité terminale
• Définition : Une fonction est récursive terminale quand le résultat de l’appel initial est directement
celui du dernier appel récursif.
• Règle : Aucune opération n’est réalisée sur le retour d’un appel récursif.
• 1 Fonction factorielle(n: in Entier; p: in Entier): Entier
• 2 Début
• 3 Si n <= 1 Alors
• 4 Résultat  p
• 5 Sinon
• 6 Résultat  factorielle(n-1, n * p)
• 7 FinSi
• 8 Fin
• Le calcul de la factorielle de 4 donne :
• fact(4) = f(4, 1)→ f(3, 4) → f(2, 12)→ f(1, 24)
•  24 24 24 24

Cours de 3GI 35
Récursivité terminale
• Remarque : Toute fonction récursive terminale peut être réécrite simplement en utilisant une itération.
• 1 Fonction factorielle(a: in Entier): Entier
• 2 Variable
• 3 n: Entier -- équivalent de a mais modifiable !
• 4 Début
• 5 n<a
• 6 Résultat  1
• 7 TantQue n > 1 Faire
• 8 Résultat  n * Résultat
• 9 n  n -1
• 10 FinTQ
• 11 Fin
• Remarque : On constate que Résultat est équivalent à p

Cours de 3GI 36
Récursivité non terminale
• Définition
• L'appel recursif n'est pas la dernière instruction et/ou elle n'est pas isolée (fait
partie d'une expression)
• plus(a,b)
• fonction plus (a,b : naturel) : naturel
• debut
• si b=0 alors
• retourner a
• sinon
• retourner 1+plus(a,b-1)
• finsi
• fin

Cours de 3GI 37
Récursivité mutuelle
• Définition
• On dit que deux algorithmes sont mutuellement récursifs si chacun des deux appelle l’autre
(éventuellement indirectement).
• Plus généralement, un ensemble d’algo est mutuellement récursif si la relation « f appelle g »
admet un cycle : f1 appelle ... appelle fn appelle f1.
• Exercice 1. La parité possède les propriétés suivantes :
• un nombre est pair s’il est nul ou si son prédecesseur est impair;
• un nombre est impair s’il est non nul et si son prédecesseur est pair.
• Écrire deux algo qui indiquent si un entier est pair ou impair.

Cours de 3GI 38
Solution
1. Fonction pair(n: in Entier): Booléen 1. Fonction impair(n: in Entier): Booléen
2. Est-ce que n est pair ? 2. Est ce que n est impair ?
3. Nécessite : n >= 0 3. Nécessite : n >= 0
4. Début 4. Début
5. Si n = 0 Alors 5. Si n = 0 Alors
6. Résultat  VRAI 6. Résultat  FAUX
7. Sinon 7. Sinon
8. Résultat  impair(n-1) 8. Résultat  pair(n-1)
9. FinSi 9. FinSi
10. Fin 10. Fin

Cours de 3GI 39
Problématiques récursives
• Il existe certains problèmes dont la définition est récursive. Ce genre
de problème se conçoit simplement à l’aide d’une fonction récursive.
• Les problèmes qui se solutionnent à l’aide de la récursivité peuvent
toujours être résolu à l’aide d’algorithme séquentiel non-récursif, mais
souvent cela est plus complexe
• Dans certains cas, l’algorithme récursif est très facile mais moins
rapide.
• Certains problèmes sont cependant très difficiles à régler de façon
non-récursive. La solution récursive est souvent facile à comprendre
(quoique difficile à trouver).
Cours de 3GI 40
Dérécursiver un algorithme
• Concerne uniquement les algorithmes récursifs terminal
• Soit les procédures suivantes

procedure P (x) procedure Q (x)


debut debut
si Cx alors tant que non Cx faire
I J
sinon x f
J fintantque
P(f ) I
finsi fin
fin
Cours de 3GI 41
Dérecursiver un algorithme
• P est équivalent à Q
• Démonstration par récurrence
Base
Soit y tel que P(y) ne fait pas d'appel recursif
Donc C est Vrai
Donc :
• P n'execute que I
• Q n'execute que I
P est equivalent a Q
Cours de 3GI 42
Démonstration
• Etape de recurrence
• On considère que P est équivalent a Q pour n appels recursifs
• Soit y tel que P(y) fait appel a n + 1 appels récursifs
• P(y) est donc :
• si Cy alors
• Iy
• sinon
• Jy
• P(fy )
• finsi
• . . . avec P(fy ) qui fait n appels recursifs

Cours de 3GI 43
Démonstration
• Or P(fy ) est equivalent a Q(fy ) • On peut généraliser l'utilisation de la variable
x
• Donc P(y) est equivalent a : • P(y) est donc équivalent a :
• si Cy alors • xy
• Iy
• si Cx alors
• sinon • Ix
• Jy • sinon
• x  fy • Jx
• tant que non Cx faire • x  fx
• Jx • tant que non Cx faire
• x  fx • Jx
• fintantque • X fx
• Ix • fintantque
• Ix
• finsi
• finsi

Cours de 3GI 44
Démonstration
• Puis intégrer Jx et x fx dans la boucle • Puis « descendre » Ix après la
tant que boucle tant que
• P(y) est donc équivalent a : • P(y) est donc équivalent a :
• xy
• x y
• si Cx alors
• Ix • tant que non Cx faire
• sinon • Jx
• tant que non Cx faire • xfx
• Jx • fintantque
• xfx
• fintantque • Ix
• Ix
• finsi
Cours de 3GI 45
Démonstration
• Enfin supprimer la variable x
• P(y) est donc équivalent a :
• tant que non Cy faire
• Jy
• yfy
• fintantque
• Iy
• Or ce code est celui de Q(y)
• Donc :
• P est équivalent a Q

Cours de 3GI 46
Conclusion
• Les algorithmes récursifs sont simples (c'est simplement une autre
façon de penser)
• Les algorithmes récursifs permettent de résoudre des problèmes
complexes
• Il existe deux types de récursivités :
• terminale, qui algorithmiquement peut être transformée en algorithme non
récursif
• non terminale
• Les algorithmes récursifs sont le plus souvent plus gourmands en
ressource que leurs équivalents itératifs
Cours de 3GI 47
Diviser pour régner
Les algorithmes de tri
Présentation générale
• Méthode de résolution des problèmes en fournissant un
algorithme récursif
• La structure générale se subdivise en 3 étapes
1. La décomposition du problème en un certain nombre de sous-
problèmes de taille réduite
2. Les appels récursifs: appliquer récursivement la fonction sur
chacune des nouvelles entrées et retourner les k solutions s1, …,sk
3. La reconstitution des solutions partielles aux sous-problèmes en la
solution s au problème

Cours de 3GI 49
Multiplication des grands entiers
• Entier représenté sur des centaines d’octets
• Opérations élémentaires
• Lecture d’1 bit
• Modification d’1 bit
• L’accès au bit suivant
• Suppression du bit de poids faible (division par 2 noté n>>1)
• Insertion d’1 nouveau bit de poids faible (multiplication par 2 noté 2<<1)

Cours de 3GI 50
Premier algorithme
Function produit(a, b:entier):entier
resultat0;
tantque b  0 faire
si estImpair(b) alors
resultat  addition(resultat,a);
a<<1; -- on multiplie a par 2
b>>1; -- on divise b par 2
fintq
retourner resultat;

Cours de 3GI 51
Analyse de l’algorithme
• La fonction addition est linéaire en la taille des entrées
• Le produit est quadratique
• (taille(a)taille(b))=(n²) avec n=taille(a)=taille(b)
• Peut-on faire mieux?

Cours de 3GI 52
Seconde version
• n=max(taille(a),taille(b))
• On suppose n pair
• a = a12n/2 + a2
• a1 est composé des n/2 bits de poids faible
• a2 des n/2 bits de poids fort
• Décomposons b de la même façon que a
• ab=a1b12n+(a1b2+a2b1)2n/2+a2b2
• ab= (a1+a2)(b1+b2)2n/2+a1b1(2n-2n/2)+a2b2(1-2n/2)

Cours de 3GI 53
Seconde version
• Pour multiplier a par b il faut
• 1. Décomposer l’entrée (a,b) en trois nouvelles entrée
(a1 + a2 , b1 + b2 ) (a1 , b1 ) (a2 , b2 )
• 2. Appliquer récursivement le produit sur chacune des entrées.
• 3. Recomposer le résultat s de la manière suivante

s = s1  2 n/2
+ s2  2 − s2  2
n n/2
+ s3 − s3  2 n/2

Cours de 3GI 54
Analyse de la complexité
• Décomposition (n)
• 3 appels récursifs sur des problèmes de taille n/2
• Reconstitution de la solution finale
• 2 additions, 2 soustractions, 4 décalages droits
• (n) pour chaque opération => (n) pour la reconstitution d’où
• f(n) = n + 3f(n/2) et f(1)=1

n  n    3 
0
 3 
1
  3 
ln 2 ( n )
ln( 3 / 2 )
f ( n ) = n + 3 + 3 2 + ...   = n   +   + ...   n    = nn ln 2

2 2   2   2   2
 
f (n) = n ln 2 ( 3)
 n1,58
Cours de 3GI 55
Proposition (Master Theorem)
f :  → R+
• Soit
 f ( n0 ) = d
 avec n0  1, b  2 et des réels k  0, a  0, c  0, d  0
 f ( n ) = af ( b ) + cn
n k

n>n0 et n/n0 est une puissance de b


Alors on a:
( )
 n si a  b
k k

 k
( )
f (n ) =  n log n si a = b k

 n ( )
 log b a
si a  b k

Cours de 3GI 56
Tri Rapide (Quicksort)
• Il est fondé sur le paradigme diviser-pour-régner
• les trois étapes du processus diviser-pour-régner sont employées pour trier un
sous-tableau typique A[p . . r].
1. Partitionnement/Diviser
• Le tableau A[p . . r] est partitionné (réarrangé) en deux sous-tableaux (éventuellement vides)
A[p . . q − 1] et A[q + 1. . r] tels que chaque élément de A[p . . q − 1] soit inférieur ou égal à
A[q] qui, lui-même, est inférieur ou égal à chaque élément de A[q + 1. . r].
• L’indice q est calculé dans le cadre de cette procédure de partitionnement.
2. Régner
• Les deux sous-tableaux A[p . . q−1] et A[q+1 . . r] sont triés par des appels récursifs au tri
rapide.
3. Combiner
• Comme les sous-tableaux sont triés sur place, aucun travail n’est nécessaire pour les
recombiner : le tableau A[p . . r] tout entier est maintenant trié.

Cours de 3GI 57
Algorithme
• TRI-RAPIDE(A, p, r)
1 si p < r alors
2 q ← PARTITION(A, p, r)
3 TRI-RAPIDE(A, p, q − 1)
4 TRI-RAPIDE(A, q + 1, r)
• Pour trier un tableau A entier, l’appel initial est TRI-RAPIDE(A, 1,
longueur[A]).

Cours de 3GI 58
Partitionnement
• Le point principal de l’algorithme est la procédure PARTITION, qui réarrange le sous-
tableau A[p . . r] sur place.
• PARTITION(A, p, r)
• 1 x ← A[r]
• 2i←p−1
• 3 pour j ← p à r − 1 faire
• 4 si A[j]  x alors
• 5 i←i+1
• 6 permuter A[i] ↔ A[j]
• fsi
• fpour
• 7 permuter A[i + 1] ↔ A[r]
• 8 retourner i + 1

Cours de 3GI 59
Analyse de l’algorithme Partition
• Au début de chaque itération de la boucle des lignes 3–6, pour tout
indice k,
• 1) Si pki, alors A[k] x.
• Sur les lignes 7–8, l’élément pivot est permuté de façon à aller entre
les deux partitions.
• 2) Si i + 1  k  j − 1, alors A[k] > x.
• 3) Si k = r, alors A[k] = x.

Cours de 3GI 60
Exercice
• Appliquer le partitionnement sur
le tableau suivant
• (2 8 7 1 3 5 6 4)

Cours de 3GI 61
Performance du tri rapide
• cas le plus défavorable
• la routine de partitionnement produit un sous problème à n−1 éléments et
une autre avec 0 élément.
• Supposons que ce partitionnement non équilibré survienne à chaque appel
récursif. Le partitionnement coûte (n)
• l’appel récursif sur un tableau de taille 0 rend la main sans rien faire, T(0) =
(1) et la récurrence pour le temps d’exécution est
• T(n) = T(n − 1)+T(0)+(n) = T(n − 1)+(n)= (n2).

Cours de 3GI 62
Cas défavorable vs tri par insertion
• Le temps d’exécution du tri rapide n’est donc pas meilleur, dans le cas
le plus défavorable, que celui du tri par insertion.
• En outre, ce temps d’exécution de (n2) se produit quand le tableau
d’entrée est déjà complètement trié
• Dans cette même situation le tri par insertion s’exécute en un temps
O(n).

Cours de 3GI 63
Cas favorable
• PARTITION produit deux sous-problèmes de taille non supérieure à
n/2
• La récurrence du temps d’exécution est alors T(n)  2T(n/2) + (n) ,
• la solution en est T(n) = O(n lg n).

Cours de 3GI 64
Tri par Tas
• Rappeler la structure d’arbre et la représentation sous forme d’un
tableau
• Revenir sur le propriétés des arbres complets
• Algorithme du tri pas tas
• Construction du tas
• Manipulation du tas

Cours de 3GI 65
Définition
• La structure de tas (binaire) est un tableau qui peut être vu comme un arbre
binaire presque complet
• Chaque nœud de l’arbre correspond à un élément du tableau qui contient la
valeur du noeud.
• Un tableau A représentant un tas est un objet ayant deux attributs :
• longueur[A], nombre d’éléments du tableau,
• et taille[A], nombre d’éléments du tas rangés dans le tableau A.
• A[1 . . longueur[A]] contient des nombres valides,
• Aucun élément après A[taille[A]], où taille[A]  longueur[A], n’est un élément du tas.

Cours de 3GI 66
Exemple de tas

Cours de 3GI 67
Fonctions usuelles
• La racine de l’arbre est A[1]
• Étant donné l’indice i d’un noeud,
• PARENT(i) : retourner i/2
• décaler i d’une position binaire vers la droite
• GAUCHE(i): retourner 2i
• décaler simplement d’une position vers la gauche la représentation binaire de i
• DROITE(i): retourner 2i +1
• décaler d’une position vers la gauche la représentation binaire de i et en ajoutant
un 1 comme bit de poids faible
• Exercice de programmation:
• Écrire chacune de ces fonctions en langage C

Cours de 3GI 68
Propriété des tas
• Dans un tas max, la propriété de tas max est que, pour chaque noeud i autre que
la racine, A[PARENT(i)]  A[i] ,
• En d’autres termes, la valeur d’un noeud est au plus égale à celle du parent.
• Ainsi, le plus grand élément d’un tas max est stocké dans la racine,
• et le sous-arbre issu d’un certain noeud contient des valeurs qui ne sont pas plus grandes que
celle du nœud lui-même.
• Un tas min est organisé en sens inverse ; la propriété de tas min est que, pour
chaque noeud i autre que la racine, A[PARENT(i)]  A[i] .
• Le plus petit élément d’un tas min est à la racine.

Cours de 3GI 69
Hauteur d’un tas
• la hauteur d’un noeud dans un tas se définit comme le nombre d’arcs
sur le chemin simple le plus long reliant le noeud à une feuille
• On définit la hauteur du tas comme étant la hauteur de sa racine.
• Comme un tas de n éléments est basé sur un arbre binaire complet,
sa hauteur est (lg n)

Cours de 3GI 70
CONSERVATION DE LA STRUCTURE DE TAS

• ENTASSER-MAX est un sous-programme qui prend en entrée un


tableau A et un indice i.
• Quand ENTASSER-MAX est appelée, on suppose que les arbres
binaires enracinés en GAUCHE(i) et DROITE(i) sont des tas max, mais
que A[i] peut être plus petit que ses enfants, violant ainsi la propriété
de tas max.
• Le rôle de ENTASSER-MAX est de faire «descendre» la valeur de A[i]
dans le tas max de manière que le sous-arbre enraciné en i devienne
un tas max.

Cours de 3GI 71
Algorithme
• ENTASSER-MAX(A, i)
Exercice:
• 1 l ← GAUCHE(i) Illustrer l’action de ENTASSER-MAX(A, 3) sur
• 2 r ← DROITE(i) le tableau
• 3 si l  taille[A] et A[l] > A[i] A = [27, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0].

• 4 alors max ← l
• 5 sinon max ← i
• 6 si r  taille[A] et A[r] > A[max]
• 7 alors max ← r
• 8 si max  i
• 9 alors échanger A[i] ↔ A[max]
• 10 ENTASSER-MAX(A, max)

Cours de 3GI 72
Analyse de l’efficacité
• en un noeud i donné, le temps (1) est nécessaire pour corriger les relations entre les éléments
A[i], A[GAUCHE(i)], et A[DROITE(i)], plus le temps d’exécuter ENTASSER-MAX sur un sous-arbre
enraciné sur l’un des enfants du noeud i.
• Les sous-arbres des enfants ont chacun une taille au plus égale à 2n/3 (le pire des cas survient
quand la dernière rangée de l’arbre est remplie exactement à moitié), et le temps d’exécution de
la procédure ENTASSER-MAX peut donc être décrit par la récurrence T(n)  T(2n/3) + (1) .
• La solution de cette récurrence, d’après le théorème général est T(n) = O(lg n).
• On peut également caractériser le temps d’exécution de ENTASSER-MAX sur un noeud de hauteur
h par O(h).
• En effet, la descente s’effectue sur une branche de l’arbre
• Or nous avons vu que la hauteur h de l’arbre est le plus long chemin de la racine à une feuille où h=lg n

Cours de 3GI 73
CONSTRUCTION D’UN TAS
• On peut utiliser la procédure ENTASSER-MAX à l’envers pour convertir
un tableau A[1 . . n], avec n = length[A], en tas max.
• En remarquant que les éléments du sous-tableau A[(n/2 + 1) . . n]
sont tous des feuilles de l’arbre
• chacun est initialement un tas à 1 élément.
• La procédure CONSTRUIRE-TAS-MAX parcourt les autres noeuds de
l’arbre et appelle ENTASSER-MAX pour chacun.

Cours de 3GI 74
Algorithme
• CONSTRUIRE-TAS-MAX(A)
•1 taille[A] ← longueur[A]
•2 pour i ← longueur[A]/2 jusqu’à 1
•3 faire ENTASSER-MAX(A, i)
• Simuler l’exécution de Construire-Tas sur le tableau A=[4 1 3 2 16 9 10 14 8 7]
• Temps d’exécution (majorant)
• Chaque appel à ENTASSER-MAX coûte O(lg n),
• il existe O(n) appels de ce type.
• Le temps d’exécution est donc O(n lg n).
• Ce majorant, quoique correct, n’est pas asymptotiquement serré.

Cours de 3GI 75
ALGORITHME DU TRI PAR TAS
• TRI-PAR-TAS(A)
• 1 CONSTRUIRE-TAS-MAX(A)
• 2 pour i ← longueur[A] jusqu’à 2
• 3 faire échanger A[1] ↔ A[i]
•4 taille[A] ← taille[A] − 1
•5 ENTASSER-MAX(A, 1)
• La procédure TRI-PAR-TAS prend un temps O(nlgn)
• l’appel à CONSTRUIRE-TAS-MAX prend un temps O(nlogn)
• chacun des n −1 appels à ENTASSER-MAX prend un temps O(lg n).

Cours de 3GI 76
A éviter
• Quand ne pas utiliser l'approche diviser-pour-regner (avec
récursivité)
• Pour que l'approche diviser-pour-regner avec récursivité conduise à
une solution efficace, il ne faut pas que l'une ou l'autre des
conditions suivantes survienne :
1. Un problème de taille n se décompose en deux ou plusieurs sous-
problèmes eux même de taille presque n (par ex., n -1).
2. Un problème de taille n se décompose en n sous problèmes de taille
n/c (pour une constante c2).

Cours de 3GI 77
Travaux Pratiques
• Programmer les algorithmes vus en cours
• Tri rapide (par segmentation)
• Tri par Tas
• Recherche dichotomique dans un tableau trié
• Contraintes
• Langage de programmation: le C/Java
• Délai de réalisation: 14 jours
• Livrables: code sources, jeux de test, un fichier readme qui détaille
l’exploitation de votre programme

Cours de 3GI 78
Programmation dynamique

Cours de 3GI 79
Position du problème

int function Fibo(int n){


if (n <= 1)
return 1 ;
else return(Fibo(n-1)+Fibo(n-2))
}

Cours de 3GI 80
Position du problème
• Version récursive
• Utilise la technique DPR
• Duplication des calculs (cf. arbre d’appel des fonctions)
• Complexité en exponentielle
• Pour calculer Fib(n), Fib(n-k) est évalué k fois
• Problème
• Réutiliser le résultat d’un calcul précédent
• Eviter (éliminer) les redondances
• Solution
• Concevoir une structure pour mémoriser les résultats obtenus

Cours de 3GI 81
DPR vs Prog. Dynamique
• Les algorithmes DPR
• Partitionnent le problème en sous-problèmes identiques et indépendants qu’ils
résolvent recursivement
• Puis combinent leurs solutions pour résoudre le problème initial
• La programmation dynamique
• Résout des problèmes en combinant des solutions des sous problèmes
• « programmation » dans ce contexte fait référence à une méthode tabulaire et non à
l’écriture de code informatique
• Domaine d’application
• Recherche opérationnelle en particulier les problèmes d’optimisation
• Il s’agit de recherche une solution optimale (minimale ou maximale) dans l’ensemble
des solutions possibles

Cours de 3GI 82
Méthode de la programmation dynamique
• Les étapes suivies peuvent être résumées comme suit :
1. Caractériser la structure d’une solution optimale => obtention de l’équation
récursive liant la solution d’un problème à celle de sous-problèmes.
2. Définir récursivement la valeur d’une solution optimale
3. Calculer la valeur d’une solution optimale de manière ascendante (bottom-up) =>
remplissage de la table. Cette étape consiste à résoudre les sous-problèmes de
taille de plus en plus grandes, en se servant bien entendu de l’équation obtenue à
l’étape 1.
4. Construire une solution optimale à partir des informations calculées.
• Remarque
• Les étapes 1-3 forment la base d’une résolution de problème à la mode de la
programmation dynamique
• On peut omettre l’étape 4 si l’on a besoin que de la valeur d’une solution optimale

Cours de 3GI 83
Illustration 1: Suite de fibonacci
int function Fib(int n){
if (Fib(n) solution est dans la table) Suppression de la récursivité
return table[n] ; Espace mémoire O(n)
if (n<= 2)
return 1;
else {
sol = Fib(n-1) + Fib(n-2) int function Fib(int n){
sauvegarder sol dans table comme solution à Fib(n) ; F[1] =1 ; F[2] =1 ;
return (sol) ; For (i=2 ; i<=n ; i++)
} F[i] = F[i-1] + F[i-2];
} return (F[i]);
}
• Utiliser un vecteur Tab tel que Tab(i) stocke Fib(i)
• On les initialise à -1
• On ne calcule Fib(i) dans une descente que si Tab(i)==-1
• Espace mémoire O(n) Cours de 3GI 84
Fibonacci (version itérative)
• Cette version est aussi efficace si on calcule de manière ascendante
• Efficacité O(n)
• Espace mémoire O(1) => moins d’espace mémoire
int fib(int n) {
int a, b, i;
a =b = 1;
pour i de 2 à n faire {
aux = b;
b = a+b; // b contient fib(i)
a = aux; // a contient fib(i-1)
}
return b;
}
Cours de 3GI 85
Etude de quelques exemples
• Calcul du coefficient binomial
• Rendre la monnaie (distributeur automatique)
• Plus longue sous-chaine
• Applications:
1. Programmation: recherche de la plus longue sous-chaine dans une chaine
de caractères
2. Biologie: recherche des séquences d’ADN
• Multiplication chaînée de matrices
• Problème du voyageur de commerce/ Sac au dos

Cours de 3GI 86
Illustration 2: coef binomiale
𝑘−1 𝑘
𝐶𝑛𝑘 =ቊ𝐶𝑛−1 + 𝐶𝑛−1 𝑠𝑖 0 < 𝑘 < 𝑛
1 𝑎𝑢𝑡𝑟𝑒𝑚𝑒𝑛𝑡

int function B(int n,k) {


if (k = = 0) || (k = = n)
return 1
else return(B(n-1,k-1) + B(n-1,k);
} \\ fin de fonction

Combien de fois est calculé 𝐶21

Cours de 3GI 87
Coef. Binomial (version itérative)
int Comb(int n, int k){
// C matrice de (n+1) ligne × (k+1) colonnes
int[][] C = new int[n+1][k+1];
C[0,0] = 1;
for(int i=1; i <= n; i++)
for(int j=0; j <= min(i, k); j++)
if (j==0) || (j==i) Complexité: Θ(nk)
C[i,j] = 1; Espace Mémoire: Θ(nk)
else // j< i
C[i,j] = C[i-1,j-1] + C[i-1,j];
return C[n,k];
}
Remarque: un tableau à une dimension suffirait pour faire ces calculs (exercice)
Cours de 3GI 88
Graphes
Représentation et algorithmes
Définition
• Un graphe orienté G = (S;A)
• S est un ensemble fini S d'éléments appelé Sommets
• A  SS dont les éléments sont appelés arcs.
• Un arc (x; y) représente une liaison orientée entre l'origine x et
l'extrémité y.
• Si (x; y) est un arc, y est un successeur de x, x est un prédécesseur de
y et si x = y
• l'arc (x; x) est appelé boucle.

Cours de 3GI 90
Définition
• Un graphe non oriente G = (S;A)
• S est un ensemble fini d'éléments appelés sommets
• A une famille de paires de S dont les éléments sont appelés arêtes.
• Etant donne un graphe oriente, sa version non orientée est obtenue
en supprimant les boucles et en substituant a chaque arc restant (x; y)
la paire {x; y}.

Cours de 3GI 91
Exemples d’application
• Gestion des réseaux de communication
• Réseau d’ordinateurs
• Carte de liaisons routières/aériennes/navales
• Ordonnancement des tâches
• contrainte de précédence entre deux tâches
• Systèmes à état
• possibilité pour un système de passer d'un état a un autre
• Plus généralement, les graphes interviennent chaque fois que l'on
veut représenter et étudier un ensemble de liaisons (orientées ou
non) entre les éléments d'un ensemble ni d'objets.

Cours de 3GI 92
Représentation
• Deux façons classiques de représenter un graphe
• par un ensemble de listes d’adjacences,
• par une matrice d’adjacences
• La représentation par listes d’adjacences est souvent préférée, car elle
fournit un moyen peu encombrant de représenter les graphes peu
denses

Cours de 3GI 93
Liste d’adjacence
• La représentation par listes d’adjacences d’un graphe G = (S, A)
consiste en un tableau Adj de #S listes, une pour chaque sommet de
S.
• Pour chaque u  S, la liste d’adjacences Adj[u] est une liste des
sommets v tels qu’il existe un arc (u, v)  A.
• Autrement dit, Adj[u] est constituée de tous les sommets adjacents à
u dans G

Cours de 3GI 94
Liste d’adjacence (Graphe non orienté)

Cours de 3GI 95
Liste d’adjacence (graphe orienté)

Cours de 3GI 96
Propriétés
• Si G est un graphe orienté, la somme des longueurs de toutes les listes d’adjacences vaut |A|, puisque
l’existence d’un arc de la forme (u, v) se traduit par la présence de v dans Adj[u].
• Si G est un graphe non orienté, la somme des longueurs de toutes les listes d’adjacences vaut 2|A|,
puisque si (u, v) est une arête, u apparaît dans la liste d’adjacences de v, et vice versa.
• Qu’un graphe soit orienté ou non, la représentation par listes d’adjacences possède la propriété avantageuse
de ne demander qu’une quantité de mémoire en O(max(S, A)) = O(S + A).
• Les listes d’adjacences peuvent aisément être adaptées aux graphes pondérés, c’est-à-dire aux graphes dont
chaque arc possède un poids associé, donné habituellement par une fonction de pondération w : A → R.
• Par exemple, soit G = (S, A) un graphe pondéré de fonction de pondération w. Le poids w(u, v) de l’arc (u, v)
 A est tout simplement stocké avec le sommet v dans la liste d’adjacences de u.
• La représentation par listes d’adjacences est assez robuste, dans le sens où elle peut être modifiée pour
supporter de nombreuses variantes sur le graphe.

Cours de 3GI 97
Matrice d’incidence
• Un inconvénient potentiel de la représentation par listes d’adjacences
est que, pour déterminer si un arc (u, v) donné est présent dans le
graphe, il n’existe pas de moyen plus rapide que de rechercher v dans
la liste d’adjacences Adj[u] soit (|Adj[u]|)
• On peut remédier à cet inconvénient en représentant le graphe par
une matrice d’adjacences, ce qui se traduira par une utilisation
asymptotiquement plus importante de la mémoire soit (1)

Cours de 3GI 98
Matrice d’adjacence
• Pour la représentation par matrice d’adjacences d’un graphe G = (S, A), on
suppose que les sommets sont numérotés arbitrairement 1,2,...|S|.
• La représentation par matrice d’adjacences d’un graphe G consiste alors en une
matrice |S|×|S|, M=(aij) telle que
• aij = 1 si (i, j)  A ,
• aij = 0 sinon .
• La matrice d’adjacences d’un graphe nécessite une quantité de mémoire en
(S2), quel que soit le nombre d’arcs du graphe.
• On remarque que la matrice d’adjacences pour un graphe non orienté est
symétrique par rapport à sa diagonale principale

Cours de 3GI 99
Matrice d’adjacence

Graphe non orienté (Diapo 87) Graphe orienté (Diapo 88)

Cours de 3GI 100


Propriétés
• On définit la transposée d’une matrice M = (aij) comme la matrice TM = (Taij) donnée par Taij = aji.
• Comme dans un graphe non orienté, (u, v) et (v, u) représentent la même arête, la matrice d’adjacences M
d’un graphe non orienté est sa propre transposée:M =TM
• Dans certaines applications, il est intéressant de ne conserver que les composantes situées sur et au-dessus
de la diagonale de la matrice d’adjacences
• Ce qui réduit presque de moitié la quantité de mémoire requise pour stocker le graphe.
• Comme les listes d’adjacences, les matrices d’adjacences peuvent aussi servir à représenter les graphes
pondérés.
• Par exemple, si G = (S, A) est un graphe pondéré associé à une fonction de pondération w, le poids w(u, v) de l’arc (u,
v)  A est simplement stocké à l’intersection de la ligne u et de la colonne v de la matrice d’adjacences.
• S’il n’existe aucun arc entre les deux sommets, on peut placer une constante NIL dans la composante
correspondante de la matrice, bien que pour de nombreux problèmes, il soit plus pratique d’utiliser une
valeur comme 0 ou .

Cours de 3GI 101


Analyse
• Les opérations d’enfilement et de défilement sont en O(1)
• le temps total des opérations de file est O(S).
• La liste d’adjacences de chaque sommet n’est balayée qu’au moment où le
sommet est défilé, la liste d’adjacences de chaque sommet est parcourue au plus
une fois. La somme des longueurs de toutes les listes d’adjacences étant (A), le
temps total consacré au balayage des listes d’adjacences est O(A).
• Le coût de l’initialisation est O(S)
• Le temps d’exécution total de PL est donc O(S+A).
• Donc, le parcours en largeur s’exécute en un temps qui est linéaire par rapport à
la taille de la représentation par listes d’adjacences de G.

Cours de 3GI 102


Chemin
• Soit G = (S;A) un graphe orienté.
• Un chemin d'origine x et d'extrémité y est une suite finie non vide de sommets
c=(s0;…; sp) telle que : s0 = x, sp = y et pour k = 0; …; p-1, (sk; sk+1) A.
• La longueur du chemin c est p, c'est le nombre d'arcs (non nécessairement
distincts) empruntés par ce chemin.
• Soit x un sommet de S, un sommet y est un ascendant (respectivement
descendant) de x s'il existe un chemin de y à x (respectivement de x à y) dans G

Cours de 3GI 103


Chemin simple et circuit
• Un chemin c = (s0,..,sp) est simple si les arcs (si-1,si); i = 1,…,p sont deux
à deux distincts.
• Un chemin c = (s0,..,sp) est élémentaire si ses sommets sont distincts
deux à deux.
• Un chemin (s0,..,sp) est un circuit si p1 et s0=sp.
• Un circuit c = (s0,..,sp) est élémentaire si le chemin (s0,..,sp-1) est
élémentaire.
• Soulignons qu'un circuit élémentaire n'est pas un chemin élémentaire
et que, de la même façon, un chemin élémentaire n'est pas un circuit
élémentaire.

Cours de 3GI 104


Chaîne et cycle
• Considérons G = (S;A) un graphe non orienté
• Une chaîne d'origine x et d'extrémité y est une suite finie de sommets
(s0; : : : ; sp) telle que s0=x, sp=y, deux sommets consécutifs
quelconques de la liste sont les extrémités d'une arête, et ces arêtes
sont distinctes deux à deux.
• Notons que si (s0,…,sp) est une chaîne, il en est de même pour
(sp,…,s0).
• Une chaîne (s0,…,sp) est un cycle si s0=sp.

Cours de 3GI 105


PARCOURS EN LARGEUR
• Position du problème
• Étant donnés un graphe G = (S, A) et un sommet origine s, le parcours en largeur emprunte
systématiquement les arcs de G pour « découvrir » tous les sommets accessibles depuis s
• Pour tout sommet v accessible depuis s, le chemin reliant s à v dans l’arborescence de
parcours en largeur correspond à un « plus court chemin » de s vers v dans G, autrement dit
un chemin contenant le plus petit nombre d’arcs.
• L’algorithme doit fonctionner aussi bien sur les graphes orientés que sur les
graphes non orientés.
• L’algorithme de parcours en largeur tient son nom au fait qu’il découvre d’abord
tous les sommets situés à une distance k de s avant de découvrir tout sommet
situé à la distance k + 1.

Cours de 3GI 106


Principe de l’algorithme
• Pour garder une trace de la progression, le parcours en largeur colorie chaque sommet en blanc,
gris, ou noir.
• Un sommet est découvert la première fois qu’il est rencontré au cours de la recherche ; il perd
alors sa couleur blanche.
• La procédure PL ci-dessous de parcours en largeur suppose que le graphe d’entrée G = (S, A) est
représenté par des listes d’adjacences.
• Pour chaque sommet du graphe, elle maintient à jour plusieurs structures de données
supplémentaires.
• La couleur de chaque sommet uS est stockée dans la variable couleur[u]
• le parent de u est stocké dans la variable [u]. Si u n’a pas de parent (par exemple, si u = s ou si u n’a pas
été découvert), alors [u] = NIL.
• La distance calculée par l’algorithme entre l’origine s et le sommet u est stockée dans d[u].
• L’algorithme a également recours à une file fifo F pour gérer l’ensemble des sommets gris.

Cours de 3GI 107


Algorithme de parcours en largeur
• PL(G, s)
• 1 pour chaque sommet u  S[G] − {s} faire
• 2 couleur[u] ← BLANC
• 3 d[u]←
• 4 [u] ← NIL
• 5 couleur[s] ← GRIS
• 6 d[s] ← 0
• 7 [s] ← NIL
• 8 F ← {s}
• 9 tant que F  ∅ faire
• 10 u ← tête[F]
• 11 pour chaque v  Adj[u] faire
• 12 si couleur[v] = BLANC alors
• 13 couleur[v] ← GRIS
• 14 d[v] ← d[u] + 1
• 15 [v] ← u
• 16 ENFILE(F, v)
• 17 DÉFILE(F)
• 18 couleur[u] ← NOIR

Cours de 3GI 108


Interprétation de l’algo
• Les lignes 1–4 colorient tous les sommets en blanc, donnent à d[u] la
valeur infinie pour chaque sommet u, et initialisent à NIL le parent de
chaque sommet
• La ligne 5 colorie l’origine s en gris, car on convient qu’il est découvert
au commencement de la procédure.
• La ligne 6 initialise d[s] à 0, et la ligne 7 donne au parent de l’origine la
valeur NIL.
• La ligne 8 initialise F en y insérant le seul sommet s ; à partir de là, F
contient constamment l’ensemble des sommets gris

Cours de 3GI 109


Interprétation de l’algo
• La boucle principale du programme, délimitée par les lignes 9–18, se
répète tant qu’il reste des sommets gris, sommets qui ont été découverts
mais dont la liste d’adjacences n’a pas été entièrement examinée. Cette
boucle tant que conserve l’invariant suivant : Dans le test fait en ligne 10,
la file F se compose des sommets gris.
• La ligne 11 détermine le sommet gris u placé en tête de la file F.
• La boucle pour des lignes 12–17 considère chaque sommet v de la liste
d’adjacences de u. Si v est blanc, c’est qu’il n’a pas encore été découvert, ce
qui est fait par les lignes 14–17. Il est d’abord colorié en gris, et sa distance
d[v] prend la valeur d[u] + 1. Ensuite, u est enregistré comme étant le
parent de v. Enfin, v est placé en queue de la file F.
• Lorsque tous les sommets de la liste d’adjacences de u ont été examinés, u
est supprimé de F et colorié en noir à la ligne 18

Cours de 3GI 110


Cours de 3GI 111
PARCOURS EN PROFONDEUR
• La stratégie suivie par un parcours en profondeur est, comme son nom l’indique,
de descendre plus «profondément» dans le graphe chaque fois que c’est possible.
• Lors d’un parcours en profondeur, les arcs sont explorés à partir du sommet v
découvert le plus récemment et dont on n’a pas encore exploré tous les arcs qui
en partent.
• Lorsque tous les arcs de v ont été explorés, l’algorithme « revient en arrière »
pour explorer les arcs qui partent du sommet à partir duquel v a été découvert.
• Ce processus se répète jusqu’à ce que tous les sommets accessibles à partir du
sommet origine initial aient été découverts

Cours de 3GI 112


Parcours en profondeur
• chaque fois qu’un sommet v est découvert pendant le balayage d’une liste
d’adjacences d’un sommet u, le parcours en profondeur enregistre cet
événement en donnant la valeur u à [v], parent de v.
• La procédure du parcours en profondeur (PP) enregistre le moment où elle
découvre le sommet u dans la variable d[u], et le moment où elle termine le
traitement du sommet u dans la variable f [u].
• Ces dates sont des entiers compris entre 1 et 2|S|, puisque découverte et fin de traitement
se produisent une fois et une seule pour chacun des |S| sommets.
• Pour tout sommet u, d[u] < f [u] .
• Le sommet u est BLANC avant l’instant d[u], GRIS entre d[u] et f [u], et NOIR
après.

Cours de 3GI 113


Algorithme
• PP(G)
• 1 pour chaque sommet u S[G]
•2 faire couleur[u] ← BLANC
•3  [u] ← NIL
• 4 date ← 0
• 5 pour chaque sommet u  S[G]
•6 faire si couleur[u] = BLANC
•7 alors VISITER-PP(u)

Cours de 3GI 114


Algorithme Visiter
• VISITER-PP(u)
• 1 couleur[u] ← GRIS /*sommet blanc u vient d’être découvert.*/
• 2 date ← date +1
• 3 d[u] ← date
• 4 pour chaque v  Adj[u] /*Exploration de l’arc (u, v).*/
• 5 faire si couleur[v] = BLANC
• 6 alors [v] ← u
• 7 VISITER-PP(v)
• 8 couleur[u] ← NOIR //noircir u, car on en a fini.
• 9 f [u] ← date ← date +1

Cours de 3GI 115


Analyse de l’efficacité
• Les boucles des lignes 1–3 et 5–7 requièrent un temps (S) sans
compter le temps d’exécution des appels VISITER-PP.
• La procédure VISITER-PP est appelée exactement une fois pour
chaque sommet vS,
• Pendant l’exécution de VISITER-PP(v), la boucle des lignes 4–7 est
exécutée |Adj[v]| fois.
• Comme vS |Adj[v]| = (A) , le coût total d’exécution des lignes 4–7
de VISITER-PP est (A).
• Le temps d’exécution de PP est donc (S + A).

Cours de 3GI 116


Applications des algorithmes
de parcours
Introduction
• Dans un problème de plus courts chemins, on possède en entrée un
graphe orienté pondéré G = (S, A), avec une fonction de pondération
w : A → R qui fait correspondre à chaque arc un poids à valeur réelle.
• La longueur du chemin p = (v0, v1,…, vk) est la somme des poids
(longueurs) des arcs qui le constituent :

k
w( p ) =  w(vi −1 , vi )
i =1

Cours de 3GI 118


Plus court chemin
• Un parcours en largeur trouve la distance entre une origine s S
donnée et chaque sommet accessible depuis s dans un graphe G = (S,
A).
• On définit la distance de plus court chemin (s, v) de s à v comme
étant :
• le nombre minimal d’arcs d’un chemin reliant le sommet s au sommet v,
•  s’il n’existe aucun chemin de s à v.
• On dit qu’un chemin de longueur (s, v) de s à v est un plus court
chemin de s à v.

Cours de 3GI 119


Plus court chemin
• Lemme : Soit G = (S, A) un graphe orienté ou non, et soit s S un sommet
arbitraire. Alors, pour tout arc (u, v)  A,
(s, v)  (s, u)+1.
• Démonstration :
• Si u est accessible depuis s, alors v l’est aussi. Dans ce cas, le plus court chemin de s à v ne
peut pas être plus long que le plus court chemin de s à u prolongé par l’arc (u, v), et l’inégalité
est donc valable. Si u ne peut pas être atteint à partir de s, alors (s, u) = ∞, et l’inégalité est
vérifiée.
• On souhaite montrer que PL calcule correctement d[v] = (s, v) pour chaque
sommet vS. On commence par montrer que d[v] est un majorant de (s, v).

Cours de 3GI 120


Variantes
• Etant donné un graphe G = (S, A), on souhaite trouver un plus court chemin depuis un
sommet origine donné sS vers n’importe quel sommet vS.
• Beaucoup d’autres problèmes peuvent être résolus par l’algorithme à origine unique,
notamment les variantes suivantes :
• Plus court chemin à destination unique : Trouver un plus court chemin vers un sommet
de destination t à partir de n’importe quel sommet v. En inversant le sens de chaque arc
du graphe, on peut ramener ce problème à un problème à origine unique.
• Plus court chemin pour un couple de sommets donné : Trouver un plus court chemin de
u à v pour deux sommets donnés u et v. Si on résout le problème à origine unique pour
le sommet origine u, on résout ce problème également. Par ailleurs, on ne connaît aucun
algorithme qui soit meilleur asymptotiquement que les meilleurs algorithmes à origine
unique dans le pire des cas.
• Plus court chemin pour tout couple de sommets : Trouver un plus court chemin de u à v
pour tout couple de sommets u et v. Ce problème peut être résolu en exécutant un
algorithme à origine unique à partir de chaque sommet ; mais on peut généralement le
résoudre plus rapidement, et sa structure est intéressante en elle-même.

Cours de 3GI 121


Algorithme de Dijkstra
• un algorithme qui permet de calculer le plus court chemin entre un sommet
particulier et tous les autres
• Numérotons les sommets du graphe G = (S, A) de 1 à n. Supposons que l'on
s'intéresse aux chemins partant du sommet 1.
• On construit un vecteur  = ((1); (2); ...; (n)) ayant n composantes tel que (j)
soit égal à la longueur du plus court chemin allant de 1 au sommet j.
• On initialise ce vecteur à c1,j, c'est-à-dire à la première ligne de la matrice des
coûts du graphe:

0 si i = j

cij =  si i  j et (i, j )  A
 (i, j ) si i  j et (i, j )  A

Cours de 3GI 122
Algorithme de Dijkstra
• On construit un autre vecteur p pour mémoriser le chemin pour aller
du sommet 1 au sommet voulu.
• La valeur p(i) donne le sommet qui précède i dans le chemin.
• On considère ensuite deux ensembles de sommets, E initialisé à {1} et
T initialisé à {2, 3, ..., n}.
• À chaque pas de l'algorithme, on ajoute à E un sommet jusqu'à ce
que E = S de telle sorte que le vecteur  donne à chaque étape le coût
minimal des chemins de 1 aux sommets de E.

Cours de 3GI 123


Description de l'algorithme de Dijkstra

• Initialisations
• 1 (j) = c1,j et p(j) = NIL, pour 1  j  n
• 2 Pour 2  j  n faire
• 3 Si c1,j <  alors p(j) = 1.
• 4 E = {1} ; T = {2, 3, ..., n}.
• Itérations
• 5 Tant que T   faire
• 6 Choisir i dans T tel que (i) est minimum
• 7 Retirer i de T et l'ajouter à E
• 8 Pour chaque successeur j de i, avec j dans T, faire
• 9 Si (j) > (i) + (i, j) alors
• 10 (j) = (i) + (i, j)
• 11 p(j) = i

Cours de 3GI 124


Fermeture transitive d’un graphe orienté
• Position du problème
• Étant donné un graphe orienté G = (S, A) où S = {1, 2, . . . , n}, on désire savoir s’il existe un chemin dans G de i vers j
pour tout couple de sommets i, j  S.
• La fermeture transitive de G est définie par le graphe G∗ = (S, A∗), où
• A∗ = {(i, j) : il existe un chemin menant du sommet i au sommet j dans G} .
• Il existe un moyen de calculer la fermeture transitive de G en (n3), qui peut permettre en pratique
d’économiser du temps et de l’espace. Cette méthode met en jeu les opérations logiques  (OU logique) et 
(ET logique)
• Pour i, j, k = 1, 2, . . . , n, on définit t(k)ij comme valant 1 s’il existe un chemin, dans le graphe G, du sommet i
au sommet j dont tous les sommets intermédiaires se trouvent dans l’ensemble {1, 2, . . . , k}, et 0 sinon.
• La fermeture transitive G∗ = (S, A∗) est construite en plaçant l’arc (i, j) dans A∗ si et seulement si t(n)ij = 1
• Une définition récursive est la suivante:
0 si i  j et (i, j )  A
tij( 0 ) = 
1 si i = j ou (i, j )  A
et pour k  1, tij( k ) = tij( k −1)  (tik( k −1)  t kj( k −1) )
Cours de 3GI 125
Algorithme

Cours de 3GI 126


Méthode PERT
• Le problème du plus long chemin dans les graphe orienté sans circuits trouve
une application dans l'ordonnancement et la planification des tâches composant
un projet complexe, par exemple la construction d'une maison.
• On fait correspondre à chaque tâche un arc d'un graphe orienté, sa durée
d'exécution étant égale au poids de cet arc. Le graphe reflète les précédences
requises dans l'exécution du projet. Ainsi, la tâche correspondant à l'arc (i, j) ne
peut commencer que si toutes les tâches correspondant à des arcs (k, i) ont été
complétées.
• Le graphe peut contenir des tâches fictives de durée nulle afin de forcer
certaines précédences.
• Les sommets du graphe représentent des événements, début (fin) des activités
correspondant aux arcs dont ils sont l'extrémité initiale (finale). Le fait que le
digraphe est sans circuit est garant de la faisabilité du projet. En effet, l'existence
d'un circuit impliquerait une contradiction dans les précédences : une tâche
devant en même temps précéder et succéder une autre
Cours de 3GI 127
Algorithme du chemin critique
• Données : G = (V, E) un graphe orienté, sans circuits, des activités avec leur durée dik.
• Notations :
• P(i) = {k  V | (k, i)  E}: c'est l'ensemble des sommets prédécesseurs de i.
• S(i) = {k V | (i, k)  E}: c'est l'ensemble des sommets successeurs de i.
• Résultat :
• - i : début au plus tôt des activités correspondant aux arcs (i, k) partant de i,
• - i : fin au plus tard des activités correspondant aux arcs (k, i) arrivant à i,
• - durée du chemin critique.
• Début
• I. Calcul des dates de début au plus tôt (récurrence en avançant dans le projet)
• 1 0
• Pour k := 2 à n faire k  max{j + djk | j  P(k)}
• II. Calcul des dates de fin au plus tard (récurrence en reculant dans le projet)
• n  n
• Pour k := n-1 à 1 faire k  min{j - dkj | j  S(k)}
• Fin
• Exercice: Calculer la complexité en temps et en espace de cet algorithme

Cours de 3GI 128


Définitions
• Un sommet i est critique si i = i.
• Un arc (i, j) est critique si ses extrémités sont des sommets critiques
et dij = j - i.
• Un chemin critique est un chemin de 1 à n n'utilisant que des arcs
critiques, c'est-à-dire des activités telles que tout retard dans leur
exécution provoquerait un retard de la fin du projet.
• La durée du chemin critique est donnée par n (ou par n, les deux
valeurs étant toujours égales). Elle correspond à la durée minimale du
projet étant données les durées des tâches le composant et les
précédences respectives.
Cours de 3GI 129
Exemple

Cours de 3GI 130

Vous aimerez peut-être aussi