CSI2510 Structures de données et algorithmes Plus court chemin
Transcription
CSI2510 Structures de données et algorithmes Plus court chemin
Graphe pondéré CSI2510 Structures de données et algorithmes 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é Plus court chemin SFO LGA HNL LAX 1 Plus court chemin DFW MIA 2 CSI2510 -- PCC Propriétés É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 Propriété 1: Un sous-chemin d’un plus court chemin est aussi un plus court chemin Propriété 2: Les réservations de vol Directions de conduite Routage des paquets d‘Internet L’ensemble des plus courts chemins d’un sommet à tous les autres sommets forme un arbre Exemple: Exemple: Plus court chemin entre Providence et Honolulu SFO Un arbre des plus courts chemins de Providence PVD ORD SFO LGA HNL LAX DFW CSI2510 -- PCC PVD ORD LGA HNL PVD ORD LAX DFW MIA 3 CSI2510 -- PCC MIA 4 1 Algorithme de Dijkstra Algorithme de Dijkstra L’algorithme conserve l’ensemble des sommets pour lesquels la distance a été calculée, appelé nuage (cloud) C 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: 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 Le graphe est connexe Les arêtes sont non-orientées Les poids des arêtes sont non-négatifs A 8 8 B 7 2 5 CSI2510 -- PCC Algorithme de Dijkstra 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 Nous mettons à jour les étiquettes des sommets adjacents à u 0 Dans l’exemple … 8 B C 3 2 E ∞ 1 8 D B C 3 2 E ∞ 5 ∞ 7 4 9 F 4 D 9 5 E F ∞ ∞ 6 2 1 D F s 4 u d(u) = 50 3 --> chemin 5 plus court! 9 d(u) = 50 d(z) = 75 z La relaxation d’une arête e consiste a mettre à jour la distance d(z) comme suit: 4 2 4 2 2 A 8 0 7 1 Mise à jour = la relaxation des arêtes Nous ajoutons au nuage le sommet extérieur u qui a la plus petite étiquette de distance 8 2 Algorithme de Dijkstra Pour chaque étape: A CSI2510 -- PCC C 3 Exemple 8 4 2 ∞ s u d(z) = 60 z d(z) ← min( d(z), d(u) + poids(e) ) 5 - chemin plus court! 11 - chemin plus court! CSI2510 -- PCC 7 CSI2510 -- PCC 8 2 Exemple Exemple (suite) 0 0 A 8 4 A 8 2 8 C 3 ∞ 2 2 7 B 0 4 4 1 D 9 E ∞ F 8 B 5 5 E 2 2 7 A 8 2 C 3 3 1 D 7 8 5 F 2 2 7 B 9 4 2 C 3 5 E 3 1 9 D 8 F 5 0 0 A 8 4 A 8 2 8 B 2 5 E C 3 4 3 1 9 D 11 F 7 7 B 5 2 2 7 5 E C 3 9 CSI2510 -- PCC D 8 F 2 5 9 Algorithme de Dijkstra 2 7 B 3 1 4 2 2 2 7 A 8 0 C 3 5 E 3 1 9 D 8 F 5 CSI2510 -- PCC 10 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. Nous emmagasinons les sommets, qui ne sont pas dans le nuage, dans une file de priorité Q. 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 {tirer u dans le nuage C} élément: un sommet v clé: D[v] la distance du sommet 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 11 CSI2510 -- PCC 12 3 D Même exemple, avec un tas 0 8 A 2 B C 4 D ∞ E D ∞ F 0 8 2 4 ∞ ∞ A B C D E F 0 A 8 4 (A,D) 4 2 8 2 2 7 B 1 C 3 ∞ 9 D RemoveMin() (A,C) 2 0 5 F 8 B RemoveMin() et mise-a-jour 0 A 8 4 4 2 (A,D) 4 (A,B) 8 (A,B) 8 A 8 ∞ E 4 2 2 7 5 E 3 3 1 C 9 Relaxation: D 11 F (C,D) 3 Mise-a-jour: 5 (C,E) 5 YES (5 < ∞) (C,F) 11 YES (11 < ∞) 2 8 B 2 2 7 5 E 3 1 C 3 YES (3 < 4) 9 D 11 F D (C,B) au lieu de 4 (C,E) 5 au lieu de (C,F) 11 au lieu de NON (9>8) 5 13 CSI2510 -- PCC 0 8 2 4 ∞ ∞ A B C D E F 0 8 2 3 A B C D ∞ ∞ E F Mise à jour signifie: enlever les anciennes clés et remplacer par les nouvelles (A,B) 8 (C,D) 3 au lieu de 4 ∞ (C,E) 5 au lieu de ∞ ∞ (C,F) 11 au lieu de ∞ Remplacer (A,D) 4 avec (C,D) 3 Insert (C,E) 5 Insert (C,F) 11 Insert (C,E) 5 Insert (C,F) 11 15 (C,D) 3 (A,B) 8 Remplacer (A,D) 4 avec (C,D) 3 CSI2510 -- PCC 14 CSI2510 -- PCC D (A,D) 4 Mise à jour signifie: enlever les anciennes clés et remplacer par les nouvelles (C,D) 3 9 Quand on doit remplacer, il faut aussi réarranger le heap (pas montré dans cet exemple) CSI2510 -- PCC 16 4 D 0 A 8 B 2 C 3 D 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 ∞ D ∞ 5 F (C,E) 5 (C,D) 3 Instead of 4 (C,E) 5 Instead of ∞ (C,F) 11 Instead of ∞ 8 2 A B C 17 3 D 5 D F 0 4 2 5 E 3 (C,D) 3 (C,E) 5 18 0 8 2 3 A B C D 5 11 E F 9 8 D 8 F B (A,B) 8 4 2 (C,D) 3 3 1 A 8 2 C F 0 A 7 11 E CSI2510 -- PCC 11 E 5 D (C,F) 11 Insert (C,E) 5 Insert (C,F) 11 0 3 (A,B) 8 Insert (C,E) 5 Insert (C,F) 11 8 2 C Remplacer (A,D) 4 avec (C,D) 3 D 8 2 B Remplacer (A,D) 4 avec (C,D) 3 CSI2510 -- PCC B 8 A Mise à jour signifie: enlever les anciennes clés et remplacer par les nouvelles (C,D) 3 (A,B) 8 0 (C,E) 5 5 2 (C,F) 11 2 7 5 E C 3 9 D 8 F (C,E) 5 3 1 (A,B) 8 (C,F) 11 5 RemoveMin() Mise à jour (D,F) 8 ? Yes 8 < 11 RemoveMin() Mis-a-jour Remplacer (C,F) 11 avec (D,F) 8 CSI2510 -- PCC 19 CSI2510 -- PCC 20 5 D 0 8 2 3 A B C D 5 E Pourquoi l‘algorithme de Dijkstra fonctionne? 8 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. F 0 A 8 4 2 8 B 2 2 7 5 E C 3 9 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. D 8 F (C,E) 5 3 1 (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 Le temps d’exécution 4 2 7 2 2 7 B C 3 5 9 E 3 1 D 8 F 5 22 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 {tirer 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: Σu∈G (1 + deg(u)) log n = O((n+m) log n) = O(m*log n) Pire cas: O(n2 log n) CSI2510 -- PCC 0 A 8 Avec une séquence non-triée: O(n) quand nous extrayons les éléments minimaux mais des mises à jour des clés plus rapides en O(1). Il y a seulement n-1 extractions et m mises à jour Le temps d’exécution est O(n2+m) = O(n2 ) En conclusion: Séquence Tas O(m log n) 23 O(n2 ) CSI2510 -- PCC 24 6