CSI2510 Structures de données et algorithmes Arbres couvrants minimaux
Arbre couvrant minimal (Minimum spanning tree) Définitions L'algorithme de Prim-Jarnik L'algorithme de Kruskal CSI2510 - ACM
Arbre couvrant minimal Sous-graphe couvrant Sous-graphe d’un graphe G contenant tous les sommets de G Arbre couvrant Sous-graphe couvrant qui est un arbre Arbre couvrant minimal (ACM) Arbre couvrant d’un graphe pondéré avec la somme minimale de poids des arêtes constituant l'arbre Applications Réseaux informatiques Réseaux routiers ORD 10 1 PIT DEN 6 7 9 3 DCA STL 4 8 5 2 DFW ATL CSI2510 - ACM
ACM versus PCC 9 9 1 1 6 7 6 7 9 9 3 3 4 4 8 5 2 8 5 2 ORD ORD PIT PIT DEN 6 DEN 7 6 7 9 9 3 DCA 3 DCA STL 4 STL 4 8 5 2 8 5 2 DFW ATL DFW ATL Arbre des plus courts chemin Arbre couvrant minimal CSI2510 - ACM 4
Propriété des cycles Soit T un arbre couvrant minimal d’un graphe pondéré G Soit e une arête de G n’appartenant pas à T et soit C le cycle obtenu lorsqu’on ajoute e à T Pour chaque arête f dans C, poids(f) poids(e) Preuve: Par contradiction Si poids(f) > poids(e) nous pouvons obtenir un arbre couvrant de plus petit poids en remplaçant e par f 8 4 2 3 6 7 9 e C f Remplacer f avec e produit un meilleur arbre couvrant 8 4 2 3 6 7 9 C e f CSI2510 - ACM
Propriété de partition U V Propriété de partition: Considérons une partition des sommets de G en deux ensembles U et V. Soit e une arête de poids minimal entre U et V. Alors, il existe un arbre couvrant minimal de G contenant e Preuve: Soit T un arbre couvrant minimal de G Si T ne contient pas e, soit C le cycle formé par l’addition de e à T et soit f une arête de C entre U et V Par la propriété de cycles, poids(f) poids(e) Alors, poids(f) = poids(e) Nous obtenons un autre ACM en remplaçant f par e 7 f 4 9 5 2 8 8 3 e 7 V Remplacer f avec e donne un autre ACM U 7 f 4 9 5 2 8 8 3 e 7 CSI2510 - ACM
L’algorithme de Prim-Jarnik L'algorithme de Prim-Jarnik pour calculer un ACM est similaire à l'algorithme de Dijkstra Nous supposons que le graphe est connexe Nous choisissons un sommet arbitraire s et nous faisons grossir l’ACM comme un nuage de sommets, commençant de s Nous emmagasinons avec chaque sommet v une étiquette d(v) représentant le plus petit poids d'une arête reliant v à un sommet du nuage (au lieu de la somme totale des poids sur un chemin du sommet de départ jusqu’à v dans Dijkstra) CSI2510 - ACM
L’algorithme de Prim-Jarnik Pour chaque étape Nous ajoutons au nuage le sommet extérieur u ayant la plus petite étiquette de distance Nous mettons à jour les étiquettes des sommets adjacents à u CSI2510 - ACM
L’algorithme de Prim-Jarnik Utiliser une file à priorité Q dont les clés sont les étiquettes D, et dont les éléments sont des paires sommet-arête Clé : distance Élément: (sommet, arête de poids minimal) Tout sommet v peut être le sommet de départ (D[v] =0) On initialise toutes les valeurs de D[u] à “infini”, mais nous initialisons aussi E[v] (l’arête associé à v) à “null” Retourne l’arbre recouvrant minimal T. Nous pouvons réutiliser le code produit par Dijkstra, et ne changer que quelques parties. Observons le pseudo-code.... CSI2510 - ACM
Algorithm PrimJarnik(G): Entrée: Un graphe pondéré G. Sortie: Un ACM T pour G. Choisir un sommer v de G {bâtir l’arbre à partir de v} T {} D[v] 0 E[v] null Pour chaque sommet u ≠ v faire D[u] ∞ Soit Q une file à priorité contenant des sommets avec les étiquettes D comme clé Tant que Q n’est pas vide (u,E(u)) Q.removeMinElement() ajouter le sommet u et l’arête E[u] à T Pour chaque sommet z adjacent à u et dans Q {effectuer la relaxation de l’arête (u, z) } if poids(u, z) < D[z] then D[z] weight(u, z) E[z] (u, z) mettre à jour D[z] retourner l’arbre T CSI2510 - ACM
Prim-Jarnik: Exemple 7 7 D 7 D 2 2 B 4 B 4 8 9 5 9 5 5 2 F 2 F C 3 3 8 8 E E A 7 A 7 7 7 7 7 7 D 2 7 D 2 B 4 B 4 5 9 5 5 9 4 2 F 5 C 2 F 8 C 8 3 8 3 8 E A E 7 7 A 7 7 CSI2510 - ACM
Prim-Jarnik: Exemple 7 7 D 2 B 4 9 4 5 5 2 F C 8 3 8 E A 3 7 7 7 D 2 B 7 D 2 B 4 5 9 4 5 2 F C 8 3 8 E A 3 7 CSI2510 - ACM
ACM versus PCC A 4 8 2 8 2 4 7 1 B C D 3 9 2 5 E F Djkstra (Shortest Path Spanning Tree) PRIM (Minimum Spanning Tree) C B A E D F 1 2 7 3 9 4 8 5 A 4 8 2 2 8 4 7 1 B C D 3 4 3 9 8 2 5 E F 11 5 CSI2510 - ACM
Prim-Jarnik L’algorithme applique la propriété des cycles Soit (u,v) l’arête minimale pour une itération donnée. S’il y a un ACM ne contenant pas (u,v), alors (u,v) complète un cycle. Puisque (u,v) a été préférée à toute autres arête connectant v au groupe, elle doit avoir un poids inférieur ou égal au poids de l’autre arête. Un nouveau ACM peut être formé par permutation CSI2510 - ACM
Prim-Jarnik: Analyse de complexité Opérations sur les graphes: Méthode incidentEdges est appelée une fois pour chaque sommet Opérations d’étiquetage: Nous plaçons/obtenons les étiquettes du sommet z O(deg(z)) fois Opérations de file de priorité (implémenté par un monceau): Chaque sommet est inséré une fois et enlevé une fois de la file à priorité, où chaque insertion ou suppression prend O(log n) La clé d'un sommet w dans la file à priorité est modifiée au plus deg(w) fois, où chaque changement de clé prend O(log n) CSI2510 - ACM
Prim-Jarnik: Analyse de complexité On effectue un retrait du monceau pour chaque nœud O(nlogn) Pour chaque nœud v, il faut mettre à jour tous ses voisins (et les réinsérer dans le monceau) O(deg(v)logn) par noeud; donc pour tous les noeuds: O(2mlogn) Rappelez-vous que Sv deg(v) = 2m L’algorithme de Prim-Jarnik est exécuté en O((n + m) log n) si le graphe est représenté par la structure de liste d’adjacence (et en utilisant un monceau) Le temps d’exécution est O(m log n) parce que le graphe est connexe CSI2510 - ACM
Dijkstra vs. Prim-Jarnik Algorithm DijkstraShortestPaths(G, s) Q new heap-based priority queue for all v G.vertices() if v = s setDistance(v, 0) else setDistance(v, ) setParent(v, ) l Q.insert(getDistance(v), v) setLocator(v,l) while !Q.isEmpty() u Q.removeMin() for all e G.incidentEdges(u) z G.opposite(u,e) r getDistance(u) + weight(e) if r < getDistance(z) setDistance(z,r) setParent(z,e) Q.replaceKey(getLocator(z),r) Algorithm PrimJarnikMST(G) Q new heap-based priority queue s a vertex of G for all v G.vertices() if v = s setDistance(v, 0) else setDistance(v, ) setParent(v, ) l Q.insert(getDistance(v), v) setLocator(v,l) while !Q.isEmpty() u Q.removeMin() for all e G.incidentEdges(u) z G.opposite(u,e) r weight(e) if r < getDistance(z) setDistance(z,r) setParent(z,e) Q.replaceKey(getLocator(z),r) CSI2510 - ACM
L’algorithme de Kruskal Chaque sommet est emmagasiné initialement comme son propre groupe. A chaque itération, l’arête de poids minimal dans le graphe est ajoutée à l'arbre couvrant si elle relie 2 groupes distincts. L'algorithme se termine quand tous les sommets sont dans le même groupe. Ceci est une application de la propriété de partition! Si l’arête minimale pour une itération donnée est (u,v), alors si nous considérons une partition de G avec u dans un groupe et v dans l’autre, alors la propriété de partition dit qu’il doit y avoir un ACM contenant (u,v) CSI2510 - ACM
L’algorithme de Kruskal Une file à priorité emmagasine les arêtes extérieures (hors du nuage) clé: poids élément: arête À la fin de l’algorithme On se retrouve avec un nuage qui entoure l’ACM Un arbre T qui est notre ACM Algorithm KruskalMST(G) Pour chaque sommet V dans G faire définir Cloud(v) de {v} Soit Q une file à priorité. Insérer toutes les arête dans Q en utilisant leur poids comme clé T Tant que T a moins que n-1 sommets Faire sommet e = Q.removeMin() Soit u, v les extrémités de e Si Cloud(v) Cloud(u) alors ajouter arête e à T Fusionner Cloud(v) et Cloud(u) return T CSI2510 - ACM
Structure de données pour l’algorithme de Kruskal L’algorithme maintient une forêt d’arbres Une arête est acceptée, si elle relie deux arbres distincts Nous avons besoin d’une structure de données qui maintient une partition c.-à-d. une collection d’ensembles disjoints, avec les opérations: find(u): retourne l’ensemble contenant u union(u,v): remplace les ensembles contenant u et v par leur union CSI2510 - ACM
Représentation d’une partition: Chaque élément d’un ensemble est mis en mémoire dans une séquence (l’ensemble pointe vers la séquence contenant ces éléments) Chaque élément à un pointeur vers l’ensemble L’opération find(u) se fait en O(1) et retourne l’ensemble dont u fait partie Pour l’opération union(u,v), nous déplaçons les éléments du plus petit ensemble dans la séquence du plus grand ensemble et nous mettons à jour leur pointeur La complexité en temps de union(u,v) est min(nu,nv), où nu et nv sont les tailles des ensembles contenant u et v Chaque fois qu’un élément est traité, il est mis dans un ensemble de taille au moins double, donc chaque élément est traité au plus log n fois donc les unions coûtent O(n log n) CSI2510 - ACM
Complexité de Kruskal La construction du monceau d’arêtes O(m log m) Chaque itération coûte un retrait du monceau et une union Chaque retrait coûte O(log m), au pire cas on fait m itérations, donc au total nous aurons O(m log m) n-1 < m < n2 donc O(log m) est toujours O( log n) Au total les unions coûtent O(n log n) parce que chaque élément est impliqué dans au plus log n unions Complexité O((n+m)log n) CSI2510 - ACM
Implémentation à base de partition Une version à base de partition de l’algorithme de Kruskal exécute les fusions des nuages comme des union(u,v) et les tests comme des find(u) Algorithm Kruskal(G): Entrée: Un graphe pondéré G. Sortie: Un ACM T pour G. Soit P une partition des sommets de G, où chaque sommet est dans un ensemble séparé. Soit Q une file à priorité gardant en mémoire les arêtes de G, ordonnées selon leur poids Soit T un arbre initialement vide Tant que T contient moins que n-1 arêtes faire (u,v) Q.removeMinElement() Si P.find(u) != P.find(v) alors Ajouter (u,v) à T P.union(u,v) retourner T Temps: O((n+m)log n) CSI2510 - ACM
Exemple G G 8 8 B 4 B 4 E 9 E 6 9 6 5 1 F 5 1 F C 3 11 C 3 11 2 2 7 H 7 H D D A 10 A 10 G G 8 8 B 4 B 4 9 E E 6 9 6 5 1 F 5 1 F C 3 C 3 11 11 2 2 7 H 7 H D D A A 10 10 CSI2510 - ACM
Exemple (suite) 2 étapes G G 8 8 B 4 B 4 E 9 E 6 9 6 5 5 1 F 1 F C 3 3 11 C 11 2 2 7 H 7 H D D A 10 A 10 4 étapes 2 étapes G G 8 8 B 4 B 4 E E 9 6 9 6 5 5 1 F 1 F C 3 C 3 11 11 2 2 7 H 7 H D D A A 10 10 CSI2510 - ACM