Trouver le plus court chemin entre deux nœuds d'un graphe pondéré est l'un des problèmes les plus classiques de l'algorithmique : calcul d'itinéraire, routage de paquets sur Internet, planification…
Dans cette tâche, vous allez :
- Implémenter l'algorithme de Dijkstra de manière naïve dans un graphe non-orienté.
- adapter Dijkstra à un problème où les coûts se multiplient au lieu de s'additionner.
Représentation des graphes
Dans toutes les fonctions, un graphe est donné par :
n: le nombre de nœuds, numérotés de0àn - 1;edges: une liste de triplets(u, v, c), oùcest le coût (ou le poids) de l'arête entreuetv;s: le nœud de départ.À noter que dans un graphe non-orienté, on considère que les 2 sens de parcours sont possibles pour chaque arrête et ont le même coût.
Chaque fonction renvoie une liste
dde longueurntelle qued[i]est la valeur optimale pour aller desài.Pour parcourir efficacement les voisins d'un nœud, construisez d'abord une liste d'adjacence. Voici un example de graphe avec sa liste d'adjacence associé.
![]()
adj = { 'a': ['b', 'c'], 'b': ['a', 'd', 'c'], 'c': ['a', 'b', 'd', 'e'], 'd': ['b', 'c', 'e', 'f'], 'e': ['c', 'd', 'f', 'g'], 'f': ['d', 'g', 'z'], 'g': ['e', 'f', 'z'], 'z': ['f', 'g'] }
Algorithme de Dijkstra
L'algorithme de Dijkstra maintient un ensemble \(N_s\) de nœuds dont la distance est définitivement connue. Cet ensemble grandit d'un nœud à chaque itération jusqu'à contenir tout le graphe :
Initialisation
\(N_s := \{s\}\), \(\bar{N_s} := N \setminus N_s\), \(d(s) := 0\) et \(d(i) := c(s, i)\) pour tout \(i \neq s\) (avec \(c(s, i) = +\infty\) s'il n'y a pas d'arête entre \(s\) et \(i\)).
Boucle — tant que \(\bar{N_s} \neq \varnothing\) :
- \(v :=\) un élément de \(\bar{N_s}\) qui minimise \(d(v)\) ;
- \(N_s := N_s \cup \{v\}\) ;
- pour tout \(i \in \bar{N_s}\) : \(d(i) := \min\big(d(i),\; d(v) + c(v, i)\big)\).
INGInious