CSI2510 Structures de données et algorithmes Plus court chemin
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é 849 PVD 1843 ORD 142 SFO 802 LGA 1743 1205 337 1387 HNL 2555 1099 LAX 1233 DFW 1120 MIA CSI2510 -- PCC
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 849 PVD 1843 ORD 142 SFO 802 LGA 1743 1205 337 1387 HNL 2555 1099 LAX 1233 DFW 1120 MIA CSI2510 -- PCC
Propriétés Propriété 1: Propriété 2: Exemple: 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 849 PVD 1843 ORD 142 SFO 802 LGA 1743 1205 337 1387 HNL 2555 1099 LAX 1233 DFW 1120 MIA CSI2510 -- PCC
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
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. A 4 8 2 2 4 8 7 1 B C D Exemple 3 9 5 2 E F CSI2510 -- PCC
3 --> chemin plus court! 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 4 8 2 A 4 8 2 8 4 7 1 2 B C D 8 2 4 3 --> chemin plus court! 8 7 1 B C D 3 9 2 5 E F 3 9 2 5 E F 5 - chemin plus court! 11 - chemin plus court! CSI2510 -- PCC
Mise à jour = la relaxation des arêtes 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 La relaxation d’une arête e consiste a mettre à jour la distance d(z) comme suit: d(u) = 50 d(z) = 75 10 u s z d(u) = 50 10 d(z) = 60 u s z d(z) min( d(z), d(u) + poids(e) ) CSI2510 -- PCC
Exemple C B A E D F 3 2 8 5 4 7 1 9 A 4 8 2 8 2 4 7 1 B C D 3 9 2 5 E F A 4 A 4 8 8 2 2 8 2 3 7 2 3 7 1 7 1 B C D B C D 3 9 3 9 5 11 5 8 2 5 2 5 E F E F CSI2510 -- PCC
Exemple (suite) A 4 8 2 7 2 3 7 1 B C D 3 9 5 8 2 5 E F A 4 8 2 7 2 3 A 4 8 2 7 2 3 7 1 B C D 3 9 5 8 2 5 E F A 4 8 2 7 2 3 7 1 B C D 3 9 5 8 2 5 E F CSI2510 -- PCC
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
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
Même exemple, avec un tas 0 8 2 4 D Même exemple, avec un tas A B C D E F A 4 8 2 8 2 4 7 1 (A,C) 2 B C D 3 9 2 5 E F (A,B) 8 (A,D) 4 RemoveMin() et mise-a-jour A 4 8 2 8 2 3 7 1 B C D 3 9 5 11 2 5 E CSI2510 -- PCC F
D Relaxation: (A,D) 4 RemoveMin() (A,B) 8 A 4 8 2 8 2 3 7 1 B C D 0 8 2 4 D A B C D E F (A,D) 4 RemoveMin() (A,B) 8 A 4 8 2 8 2 3 7 1 B C D Relaxation: (C,D) 3 YES (3 < 4) 3 9 Mise-a-jour: 5 11 2 5 E F (C,E) 5 YES (5 < ) (C,F) 11 YES (11 < ) (C,B) 9 NON (9>8) CSI2510 -- PCC
D Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 0 8 2 4 D 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 (A,B) 8 au lieu de (C,E) 5 (C,F) 11 au lieu de Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 CSI2510 -- PCC
Remplacer (A,D) 4 avec (C,D) 3 0 8 2 3 D A B C D E F Mise à jour signifie: enlever les anciennes clés et remplacer par les nouvelles (C,D) 3 (C,D) 3 au lieu de 4 (A,B) 8 au lieu de (C,E) 5 (C,F) 11 au lieu de Quand on doit remplacer, il faut aussi réarranger le heap (pas montré dans cet exemple) Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 CSI2510 -- PCC
D Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 0 8 2 3 5 D A B C D E F Mise à jour signifie: enlever les anciennes clés et remplacer par les nouvelles (C,D) 3 (C,D) 3 au lieu de 4 (A,B) 8 (C,E) 5 au lieu de (C,E) 5 (C,F) 11 au lieu de Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 CSI2510 -- PCC
D Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 0 8 2 3 5 11 D A B C D E F Mise à jour signifie: enlever les anciennes clés et remplacer par les nouvelles (C,D) 3 (C,D) 3 Instead of 4 (A,B) 8 (C,E) 5 Instead of (C,E) 5 (C,F) 11 Instead of (C,F) 11 Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 CSI2510 -- PCC
D RemoveMin() Mis-a-jour C B A E D F 3 2 8 5 4 7 1 9 (C,D) 3 (A,B) 8 0 8 2 3 5 11 D A B C D E F C B A E D F 3 2 8 5 4 7 1 9 (C,D) 3 (A,B) 8 (C,E) 5 (C,F) 11 RemoveMin() Mis-a-jour CSI2510 -- PCC
Mise à jour (D,F) 8 ? Yes 8 < 11 0 8 2 3 5 11 D A B C D E F C B A E D F 3 2 8 5 4 7 1 9 (C,E) 5 (A,B) 8 (C,F) 11 RemoveMin() Mise à jour (D,F) 8 ? Yes 8 < 11 Remplacer (C,F) 11 avec (D,F) 8 CSI2510 -- PCC
Mise à jour (D,F) 8 ? Yes 8 < 11 0 8 2 3 5 8 D A B C D E F C B A E D F 3 2 8 5 4 7 1 9 (C,E) 5 (A,B) 8 (D,F) 8 RemoveMin() Mise à jour (D,F) 8 ? Yes 8 < 11 Remplacer (C,F) 11 avec (D,F) 8 CSI2510 -- PCC
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. A 8 4 2 7 2 3 7 1 B C D 3 9 5 8 2 5 E F CSI2510 -- PCC
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
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