CSI2510 Structures de données et algorithmes Plus court chemin 1 Graphe pondéré Les poids des arêtes d’un graphe représentent des distances, des coûts, etc. Exemple d’un graphe pondéré non-orienté: Dans un graphe des route aériennes, le poids d'une arête représente la distance en miles entre les aéroports de chaque extrémité SFO PVD ORD LGA HNL LAX DFW CSI2510 -- PCC MIA 2 Plus court chemin Étant donné un graphe pondéré et deux sommets u et v, nous voulons trouver un chemin de poids total minimal entre u et v Applications Les réservations de vol Directions de conduite Routage des paquets d‘Internet Exemple: Plus court chemin entre Providence et Honolulu SFO PVD ORD LGA HNL LAX DFW CSI2510 -- PCC MIA 3 Propriétés Propriété 1: Un sous-chemin d’un plus court chemin est aussi un plus court chemin Propriété 2: L’ensemble des plus courts chemins d’un sommet à tous les autres sommets forme un arbre Exemple: Un arbre des plus courts chemins de Providence SFO PVD ORD LGA HNL LAX DFW CSI2510 -- PCC MIA 4 Algorithme de Dijkstra La distance entre un sommet v à un autre sommet s est la longueur du plus court chemin entre s et v L’algorithme de Dijkstra calcule la distance entre un sommet donnée s de départ et tous les autres sommets Suppositions: Le graphe est connexe Les arêtes sont non-orientées Les poids des arêtes sont non-négatifs CSI2510 -- PCC 5 Algorithme de Dijkstra L’algorithme conserve l’ensemble des sommets pour lesquels la distance a été calculée, appelé nuage (cloud) C On fait grossir un “nuage” de sommets, contenant au départ s et couvrant éventuellement tous les sommets Pour chaque sommet v nous emmagasinons d(v) = La plus courte distance entre v et s dans le sous-graphe constitué du nuage et de ses sommets adjacents. 0 A 8 2 8 B 7 Exemple 3 2 CSI2510 -- PCC C 4 2 1 9 E F 6 D 5 4 Algorithme de Dijkstra Pour chaque étape: Nous ajoutons au nuage le sommet extérieur u qui a la plus petite étiquette de distance Nous mettons à jour les étiquettes des sommets adjacents à u Dans l’exemple … A 8 2 8 B 8 7 C 3 2 E 0 1 8 D 4 B 2 E 5 2 1 C 7 3 9 F 4 2 4 2 A 8 0 D 4 3 --> chemin 5 plus court! 9 F 5 - chemin plus court! 11 - chemin plus court! CSI2510 -- PCC 7 Algorithme de Dijkstra Mise à jour = la relaxation des arêtes Considérer une arête e = (u,z) telle que: u est le sommet le plus récemment ajouté au nuage z n’est pas dans le nuage d(u) = 50 s La relaxation d’une arête e consiste a mettre à jour la distance d(z) comme suit: u d(u) = 50 s u d(z) = 75 z d(z) = 60 z d(z) min( d(z), d(u) + poids(e) ) CSI2510 -- PCC 8 Exemple A 8 0 4 A 8 2 B 8 7 2 C 2 1 D 9 E F A 8 4 5 B 8 7 5 E 2 C 3 B 2 7 5 E D 8 A 8 3 5 0 4 2 C 3 1 9 0 4 2 F 2 8 4 2 3 0 2 1 9 D 11 F 3 5 B 2 CSI2510 -- PCC 7 7 5 E C 3 2 1 9 D 8 F 3 5 9 Exemple (suite) A 8 0 4 2 B 2 7 7 C 3 5 E 2 1 9 D 8 F 3 5 A 8 0 4 2 B 2 CSI2510 -- PCC 7 7 C 3 5 E 2 1 9 D 8 F 3 5 10 Algorithme de Dijkstra Nous emmagasinons les sommets, qui ne sont pas dans le nuage, dans une file de priorité Q. élément: un sommet v clé: D[v] la distance du sommet CSI2510 -- PCC 11 Algorithme de Dijkstra Algorithm ShortestPath(G, v): Entrés : Un graphe pondéré G et un sommet particulier v de G. Sortie : Une étiquette D[u], pour chaque sommet u de G, telle que D[u] est la longueur d'un plus court chemin de v à u dans G. initialise D[v] 0 et D[u] ∞ pour chaque sommet v u Soit Q une file à priorité qui contient tous les sommets de G utilisant les étiquettes de D comme clés. while Q do {insérer u dans le nuage C} u Q.removeMinElement() pour chaque sommet z adjacent à u tel que z est dans Q faire {exécuter l'opération de relaxation sur l’arête (u, z) } Si D[u] + w((u, z)) < D[z] alors D[z] D[u] + w((u, z)) changer la valeur de la clé de z dans Q à D[z] Retourner l’étiquette D[u] de chaque sommet u. CSI2510 -- PCC 12 D Même exemple, avec un tas A 8 0 8 2 4 A B C D E F 0 4 2 B 2 8 7 C 3 2 1 9 D E F A 8 4 (A,C) 2 5 (A,B) 8 (A,D) 4 RemoveMin() et mise-a-jour 0 4 2 B 2 8 7 5 E C 3 2 1 9 D 11 F 3 5 CSI2510 -- PCC 13 D 0 8 2 4 A B C D E F (A,D) 4 RemoveMin() A 8 (A,B) 8 0 4 2 B 2 8 7 5 E C 3 2 1 9 D 11 F 3 Relaxation: Mise-a-jour: 5 (C,D) 3 YES (3 < 4) (C,E) 5 YES (5 < ) (C,F) 11 YES (11 < ) (C,B) CSI2510 -- PCC 9 NON (9>8) 14 D 0 8 2 4 A B C D E F (A,D) 4 Mise à jour signifie: enlever les anciennes clés et remplacer par les nouvelles (C,D) 3 au lieu de 4 (C,E) 5 au lieu de (C,F) 11 au lieu de (A,B) 8 Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 CSI2510 -- PCC 15 D 0 8 2 3 A B C D E F Mise à jour signifie: enlever les anciennes clés et remplacer par les nouvelles (C,D) 3 au lieu de 4 (C,E) 5 au lieu de (C,F) 11 au lieu de (A,B) 8 Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 (C,D) 3 Quand on doit remplacer, il faut aussi réarranger le heap (pas montré dans cet exemple) CSI2510 -- PCC 16 D 0 8 2 A B C 3 D 5 E Mise à jour signifie: enlever les anciennes clés et remplacer par les nouvelles (C,D) 3 au lieu de 4 (C,E) 5 au lieu de (C,F) 11 au lieu de F (C,D) 3 (A,B) 8 (C,E) 5 Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 CSI2510 -- PCC 17 D 0 8 2 A B C 3 5 D 11 E Mise à jour signifie: enlever les anciennes clés et remplacer par les nouvelles (C,D) 3 Instead of 4 (C,E) 5 Instead of (C,F) 11 Instead of F (C,D) 3 (A,B) 8 (C,E) 5 (C,F) 11 Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 CSI2510 -- PCC 18 D A 8 0 8 2 A B C 3 D 5 11 E 0 4 2 B 2 8 7 5 E C 3 F 2 1 9 D 8 F (C,D) 3 3 (A,B) 8 (C,E) 5 5 (C,F) 11 RemoveMin() Mis-a-jour CSI2510 -- PCC 19 D A 8 0 8 2 3 A B C D 5 11 E 0 4 2 B 2 8 7 5 E C 3 F 2 1 9 D 8 F (C,E) 5 3 (A,B) 8 (C,F) 11 5 RemoveMin() Mise à jour (D,F) 8 ? Yes 8 < 11 Remplacer (C,F) 11 avec (D,F) 8 CSI2510 -- PCC 20 D A 8 0 8 2 3 A B C D 5 E B 2 7 5 E C 3 F 0 4 2 8 8 2 1 9 D 8 F (C,E) 5 3 (A,B) 8 (D,F) 8 5 RemoveMin() Mise à jour (D,F) 8 ? Yes 8 < 11 Remplacer (C,F) 11 avec (D,F) 8 CSI2510 -- PCC 21 Pourquoi l‘algorithme de Dijkstra fonctionne? L’algorithme de Dijkstra utilise un algorithme glouton. C’est-à-dire un algorithme qui effectue à chaque étape le choix optimal local dans l’espoir d’arriver à la solution optimale globale. Supposons qu'il n'a pas trouvé toutes les plus courtes distances. Soit F le premier mauvais sommet que l'algorithme a traité. Quand le nœud précédent, D, sur le vrai plus court chemin a été considéré, sa distance était correcte. Mais l’arête (D,F) a été relaxée à ce moment-là! Ainsi, aussi longtemps que d(F)>d(D) la distance de F ne peut pas être fausse. C'est-à-dire, il n'y a pas de mauvais sommet. CSI2510 -- PCC A 8 0 4 2 B 2 7 7 C 3 5 E 2 1 9 D 8 F 5 22 3 Le temps d’exécution Si nous représentons G avec une liste d’adjacence, alors nous pouvons parcourir tous les sommets adjacents à u pendant un temps proportionnel à deg(u) La file de priorité Q Avec heap. while Q do {insérer u dans le nuage C} A chaque itération: - Extraction des sommets avec la distance la plus petite: O(log n). - Mises à jour des clés: O(log n) pour chaque mise à jour (remplacer une clé et insérer dans le tas)=>Apres chaque extraction (deg(u) mises à jour): O(deg(u) log n) En total: uG (1 + deg(u)) log n = O((n+2m) log n) = O(m*log n) Pire cas: O(n2 log n) CSI2510 -- PCC 23 Le temps d’exécution Avec une séquence non-triée: O(n) quand on extrait les éléments minimaux mais des mises à jour des clés plus rapides en O(1). Il y a n-1 extractions d’ordre n et m mises à jour d’ordre constant. Le temps d’exécution est O(n2+m) = O(n2 ) En conclusion: Séquence Monceau O(m log n) O(n2 ) CSI2510 -- PCC 24