L'algorithme de Dijkstra, à la main, animé et en Python
CoursGraphes pondérés
Dans un graphe pondéré, chaque arête porte un nombre, son poids : une distance en km, une durée en minutes, un prix… La longueur d'une chaîne est alors la somme des poids de ses arêtes.
Les GPS et les sites d'itinéraires cherchent la chaîne de plus petit poids entre deux sommets. L'algorithme le plus célèbre pour cela a été inventé par Edsger Dijkstra en 1956.
Au départ : écris 0 sur le sommet de départ et ∞ sur tous les autres.
Choisis le sommet non traité qui a la plus petite valeur : c'est le sommet actif. Entoure-le.
Regarde ses voisins non traités. Pour chacun, calcule : valeur du sommet actif + poids de l'arête.
Si ce nombre est plus petit que la valeur du voisin : remplace la valeur, trace en couleur l'arête qui vient du sommet actif, et raye l'ancienne arête colorée qui arrivait à ce voisin (s'il y en avait une).
Si ce nombre est plus grand ou égal : ne change rien.
Le sommet actif est maintenant traité : encadre sa valeur, elle ne changera plus.
Recommence à l'étape 2 jusqu'à ce que tous les sommets soient traités.
À la fin, la valeur de chaque sommet est sa distance au départ, et les arêtes colorées forment les plus courts chemins.
Graphe de la fiche méthode : distances depuis A.
Exemple : le graphe de la fiche méthode, depuis A
Départ : 0 sur A, ∞ sur tous les autres sommets.
Sommet actif A. B reçoit 3 et E reçoit 2 : on trace A–B et A–E.
Sommet actif E (car 2 < 3). F reçoit 2 + 5 = 7 et D reçoit 2 + 5 = 7 : on trace E–F et E–D. Vers B : 2 + 5 = 7, plus grand que 3, rien à faire.
Sommet actif B (3). Vers F : 3 + 1 = 4 < 7, on raye E–F et on trace B–F. Vers D : 3 + 4 = 7, égalité, rien à faire. Vers C : 3 + 2 = 5, on trace B–C.
Sommet actif F (4). Vers D : 4 + 2 = 6 < 7, on raye E–D et on trace F–D.
Sommet actif C (5). Vers D : 5 + 2 = 7, pas mieux que 6, rien à faire.
Dernier sommet D (6) : terminé.
Pour aller de A à D : A–B–F–D, longueur 6. Pour aller en C : A–B–C, longueur 5.
Vigilance
En cas d'égalité (par exemple B → D donne 7, comme E → D), on ne change rien : l'ancien chemin est aussi court.
Une valeur encadrée (sommet traité) ne change plus jamais.
Voir l'algorithme en action
L'animation Dijkstra rejoue l'algorithme pas à pas sur les graphes du cours. En mode pédagogique, c'est toi qui choisis le sommet suivant et qui calcules les distances. Tu peux aussi y construire ton propre graphe.
ExercicesChercher le plus court chemin
EX 45Je m'entraîne🌶️🌶️application
Exercice 45 — De A à F
Les nombres sont des distances en kilomètres.
Applique l'algorithme de Dijkstra depuis A, en redessinant le graphe à chaque étape comme dans la méthode.
Quel est le plus court chemin de A à F ? Quelle est sa longueur ?
Vérifie avec l'animation (graphe « TP : de A à F »).
Indice 1
Premier sommet actif : A. Ses voisins B et C reçoivent 3 et 1.
Indice 2
Deuxième sommet actif : C (valeur 1).
📝 réponses dans ton compte rendu, exercice 45
EX 46Je m'entraîne🌶️🌶️🌶️plusieurs étapes
Exercice 46 — Un dernier pour la route
Graphe à sept sommets.
Applique l'algorithme de Dijkstra depuis S, en redessinant le graphe à chaque étape.
Quel est le plus court chemin de S à E ? Sa longueur ?
Le chemin direct S–U fait 20. Pourquoi n'est-il pas utilisé ?
Indice
Un chemin avec plus d'arêtes peut être plus court qu'une arête directe.
📝 réponses dans ton compte rendu, exercice 46
EX 47Je m'entraîne🌶️🌶️application
Exercice 47 — Mon graphe dans l'animation
Dans l'animation, choisis l'exemple « Un dernier pour la route », passe en mode pédagogique et refais l'algorithme depuis S : c'est toi qui choisis chaque sommet et qui calcules les distances.
Puis, dans « Construire mon propre graphe », invente un graphe de 6 sommets où le chemin le plus court entre deux sommets utilise au moins 4 arêtes. Fais une capture d'écran.
Indice
Dans « Construire mon propre graphe », une ligne = une arête : ses deux sommets et son poids.
📝 réponses dans ton compte rendu, exercice 47
PythonDes itinéraires réels
Le module pyroutelib3 calcule un vrai itinéraire en téléchargeant les rues d'OpenStreetMap, puis en appliquant un algorithme de plus court chemin de la famille de Dijkstra.
Installe le module pyroutelib3 comme tu as installé Folium.
Copie et exécute le programme ci-dessous (il faut une connexion Internet : le premier calcul peut prendre une minute).
itineraire.py
import folium
import pyroutelib3
# le réseau des chemins piétons, téléchargé au fur et à mesure
graphe = pyroutelib3.osm.LiveGraph(pyroutelib3.osm.FootProfile())
depart = graphe.find_nearest_node((44.16213, 4.617122))
arrivee = graphe.find_nearest_node((44.163942, 4.611689))
chemin = pyroutelib3.find_route_without_turn_around(graphe, depart.id, arrivee.id)
points = [graphe.get_node(n).position for n in chemin]
carte = folium.Map(location=[44.163, 4.614], zoom_start=16)
folium.PolyLine(points, color="red", weight=5).add_to(carte)
folium.Marker(points[0], popup="Départ").add_to(carte)
folium.Marker(points[-1], popup="Arrivée").add_to(carte)
carte.save("itineraire.html")
EX 48Je m'entraîne🌶️🌶️application
Exercice 48 — Mon itinéraire
Exécute le programme et ouvre itineraire.html. Combien de points la variable points contient-elle ? (Ajoute print(len(points)).)
Modifie le programme pour tracer un itinéraire à pied de ton choix, par exemple de la gare au lycée.
Remplace FootProfile() par CarProfile(). Le trajet change-t-il ? Pourquoi ?
Compare la longueur de ton trajet à pied avec celle donnée par l'outil Itinéraire de cartes.gouv.fr.
Indice
FootProfile suit les chemins piétons, CarProfile les routes ouvertes aux voitures (et leurs sens interdits).
💾 NOM_Prenom_ex48.py
EX 49Je m'entraîne🌶️🌶️🌶️🌶️défi
Exercice 49 — Dijkstra en Python
Défi : voici un programme qui applique l'algorithme de Dijkstra. Le graphe est un dictionnaire : pour chaque sommet, la liste de ses voisins avec le poids de l'arête.
dijkstra.py
graphe = {
"A": {"B": 3, "E": 2},
"B": {"A": 3, "C": 2, "D": 4, "E": 5, "F": 1},
"C": {"B": 2, "D": 2},
"D": {"B": 4, "C": 2, "E": 5, "F": 2},
"E": {"A": 2, "B": 5, "D": 5, "F": 5},
"F": {"B": 1, "D": 2, "E": 5},
}
defdijkstra(graphe, depart):
distance = {s: float("inf") for s in graphe}
venant_de = {s: Nonefor s in graphe}
distance[depart] = 0
a_traiter = list(graphe)
while a_traiter:
actif = min(a_traiter, key=lambda s: distance[s])
a_traiter.remove(actif)
for voisin, poids in graphe[actif].items():
if distance[actif] + poids < distance[voisin]:
distance[voisin] = distance[actif] + poids
venant_de[voisin] = actif
return distance, venant_de
defchemin(venant_de, arrivee):
etapes = [arrivee]
while venant_de[etapes[0]] isnotNone:
etapes.insert(0, venant_de[etapes[0]])
return"-".join(etapes)
distance, venant_de = dijkstra(graphe, "A")
for s in distance:
print(s, distance[s], chemin(venant_de, s))
Exécute le programme : retrouves-tu les résultats de la fiche méthode ?
Modifie le dictionnaire pour qu'il représente le graphe de l'exercice 45, et vérifie ta réponse.
Fais de même pour le graphe de l'exercice 46.
Indice
Chaque arête apparaît deux fois dans le dictionnaire : une fois dans chaque sens.
💾 NOM_Prenom_ex49.py
Synthèse
Dans un graphe pondéré, la longueur d'une chaîne est la somme des poids.
Dijkstra : on fixe à chaque étape le sommet non traité le plus proche du départ, et on améliore ses voisins.
Les GPS utilisent des algorithmes de la même famille sur le graphe des routes.