Université Joseph Fourier RICM3 Polytech Grenoble Année 2014–2015 Algorithmique avancée — TD no 6 : Algorithme de Dijkstra Soit un graphe G = (S, A). Les arcs sont étiquetés au moyen d’une fonction ω : A → R. L’algorithme de Dijkstra permet de déterminer le chemin de poids minimal entre deux sommets s0 et s1 , le poids d’un chemin étant défini par la somme des étiquettes des arcs de ce chemin. Algorithme de Dijkstra : Dijkstra(s0 ) : s ∈ S : d[s] ← +∞ d [ s0 ] ← 0 Q ← { s0 } tant que Q 6 = ∅ u ← arg mins {d[s]|s ∈ Q} Q ← Q − {u} pour tout v t.q. ( u, v ) ∈ A pv ← d[u] + ω (u, v) si pv < d [ v ] alors d[v] ← pv Q ← Q ∪ {v} pour tout Exercice 1. Cet algorithme termine-t-il toujours ? Si non, sous quelle(s) hypothèse(s) termine-t-il ? L’algorithme ne termine pas s’il contient un circuit de poids négatif, atteignable depuis s0 . Quelques conditions suffisantes (mais pas forcément nécessaires !) pour que l’algorithme termine : — le poids des arcs est positif ou nul — il n’existe pas de circuit de poids négatif — il n’existe pas de circuit de poids négatif atteignable depuis s0 (condition nécessaire et suffisante). Exercice 2. Exécutez à la main cet algorithme sur le graphe suivant (avec s0 = A) : 3 A 5 4 B 2 1 4 1 E 2 C D 1 Notez les valeurs de d et de Q à la fin de chaque itération. 0 1 2 3 4 5 A 0 0 0 0 0 0 B +∞ 3 3 3 3 3 1. Que représente d à la fin de l’exécution ? d C +∞ 5 4 4 4 4 D E Q +∞ +∞ { A} +∞ +∞ { B, C } 7 4 {C, D, E} 7 4 { D, E} 6 4 {D} 6 4 ∅ u A B C E D Pour tout s ∈ S, d[s] est le poids du plus court chemin de s0 à s. 2. Que peut-on dire de la séquence de valeurs d[s] (pour un s donné) ? La séquence de valeur est décroissante : on ne modifie la valeur de d[s] que lors de l’instruction d[v] ← pv, exécutée seulement si pv < d[v]. 3. Donnez un invariant concernant la valeur de d. Soit δs le poids du plus court chemin de s0 à s, on a d[s] ≥ δs . Exercice 3. On suppose que tous les sommets du graphe sont atteignables depuis s0 . Donner un minorant et un majorant du nombre d’insertions dans Q (nombre d’évaluations de «Q ← Q ∪ {v}»). Minorant du nombre d’insertions : on insère une et une seule fois chaque sommet : |S|. Ce minorant est atteint pour tout graphe de la forme : s0 s1 s2 sn ··· Majorant du nombre d’insertions (en supposant que le graphe ne comporte aucun circuit de poids négatif ; sinon la question n’a pas de sens) : à chaque itération, la valeur de d[u] croît, puisqu’on prend le sommet u ∈ Q tel que d[u] est minimum, et qu’on ajoute ensuite dans Q uniquement des sommets v tels que d[v] > d[u]. Soit |S| = n : tout sommet du graphe est traité une et une seule fois (il ne peut être réinséré dans Q puisque d[u] est croissant, et ∀v, d[v] décroissant). Dans le pire cas, à chaque itération, on va «insérer» à nouveau tous les sommets non encore traités. Le majorant du n ( n −1) nombre d’insertions est donc ∑in=1 (n − i ) = 2 . Exercice : construire un graphe (de 5 sommets) pour lequel ce majorant est atteint. En déduire une estimation du coût de l’algorithme (réfléchir à cette occasion à l’implémentation de Q !). Q est une file à priorité. Il y a n extractions et O(n2 ) «insertions» (ou modification de la priorité) dans Q. Le coût «critique» est ici celui de l’insertion. On peut implémenter Q de manière à avoir l’insertion/modification de la priorité en O(1), et l’extraction en O(n) (par exemple si Q est implémenté par un tableau de booléens indicé par les sommets). Le coût de l’algorithme est alors en O(n2 ) (n extractions en O(n), et O(n2 ) insertions en O(1)). Exercice 4. Modifier cet algorithme pour afficher le chemin de poids minimal entre deux sommets s0 et s1 donnés. Il faut mémoriser, pour chaque sommet, le sommet précédent, c’est-à-dire celui depuis lequel on a calculé le plus court chemin. Cette valeur est mise à jour lors de la mise à jour de d. On utilise un tableau P de sommets, indicé par les sommets : Dijkstra(s0 ) : pour tout s ∈ S : d[s] ← +∞ P[s] ← s d [ s0 ] ← 0 Q ← { s0 } Q 6= ∅ u ← arg mins {d[s]|s ∈ Q} Q ← Q − {u} v (u, v) ∈ A pv ← d[u] + ω (u, v) pv < d[v] d[v] ← pv P[v] ← u Q ← Q ∪ {v} tant que pour tout t.q. si Pour afficher un plus court chemin entre s0 et s : AcherChemin(s): si P[s] 6= s alors AcherChemin(P[s]) Acher(s) alors
© Copyright 2024