diff --git a/slides/cours_24.md b/slides/cours_24.md index f20a9fd1e7c95a7280feda6d8a82e0fdce792dbf..7e30b5f506754ad63655f415b306422897033390 100644 --- a/slides/cours_24.md +++ b/slides/cours_24.md @@ -29,7 +29,8 @@ date: "2023-05-24" ```C initialiser(graphe) // tous sommets sont non-visités -file = visiter(sommet, vide) // sommet est un sommet du graphe au hasard +file = visiter(sommet, vide) // sommet est un sommet + // du graphe tant que !est_vide(file) v = défiler(file) file = visiter(v, file) @@ -102,7 +103,8 @@ graph LR; ```C initialiser(graphe) // tous sommets sont non-visités -pile = visiter(sommet, vide) // sommet est un sommet du graphe au hasard +pile = visiter(sommet, vide) // sommet est un + // sommet du graphe tant que !est_vide(pile) v = dépiler(pile) pile = visiter(v, pile) @@ -261,100 +263,11 @@ si distance(u,v) > distance(u,w) + distance(w,v) on passe par w plutôt qu'aller directement ``` -# Algorithme de Dijkstra - -## Idée générale - -* On assigne à chaque noeud une distance $0$ pour $s$, $\infty$ pour les autres. -* Tous les noeuds sont marqués non-visités. -* Depuis du noeud courant, on suit chaque arête du noeud vers un sommet non visité et on calcule le poids du chemin à chaque voisin et on met à jour sa distance si elle est plus petite que la distance du noeud. -* Quand tous les voisins du noeud courant ont été visités, le noeud est mis à visité (il ne sera plus jamais visité). -* Continuer avec le noeud à la distance la plus faible. -* L'algorithme est terminé losrque le noeud de destination est marqué comme visité, ou qu'on a plus de noeuds qu'on peut visiter et que leur distance est infinie. - -# Algorithme de Dijkstra - -## Pseudo-code (5min, matrix) - -. . . - -```C -tab dijkstra(graph, s, t) - pour chaque v dans graphe - distance[v] = infini - q = ajouter(q, v) - distance[s] = 0 - tant que non_vide(q) - u = min(q, distance) // plus petite distance dans q - si u == t - retourne distance - q = remove(q, u) - // voisin de u encore dans q - pour chaque v dans voisinage(u, q) - n_distance = distance[u] + w(u, v) - si n_distance < distance[v] - distance[v] = n_distance - retourne distance -``` - -# Algorithme de Dijkstra +# Algorithme de Dijkstra (1 à 5) -* Cet algorithme, nous donne le plus court chemin mais... -* ne nous donne pas le chemin! - -## Comment modifier l'algorithme pour avoir le chemin? - -. . . - -* Pour chaque nouveau noeud à visiter, il suffit d'enregistrer d'où on est venu! -* On a besoin d'un tableau `précédent`. - -## Modifier le pseudo-code ci-dessus pour ce faire (3min matrix) - -# Algorithme de Dijkstra - -```C -tab, tab dijkstra(graph, s, t) - pour chaque v dans graphe - distance[v] = infini - précédent[v] = indéfini - q = ajouter(q, v) - distance[s] = 0 - tant que non_vide(q) - u = min(q, distance) // plus petite distance dans q - si u == t - retourne distance - q = remove(q, u) - // voisin de u encore dans q - pour chaque v dans voisinage(u, q) - n_distance = distance[u] + w(u, v) - si n_distance < distance[v] - distance[v] = n_distance - précédent[v] = u - retourne distance, précédent -``` - -# Algorithme de Dijkstra - -## Comment reconstruire un chemin ? - -. . . - -```C -pile parcours(précédent, s, t) - sommets = vide - u = t - // on a atteint t ou on ne connait pas de chemin - si u != s && précédent[u] != indéfini - tant que vrai - sommets = empiler(sommets, u) - u = précédent[u] - si u == s // la source est atteinte - retourne sommets - retourne sommets -``` - -# Algorithme de Dijkstra +* $D$ est le tableau des distances au sommet $1$: $D[7]$ est la distance de 1 à 7. +* Le chemin est pas forcément direct. +* $S$ est le tableau des sommets visités. ::: columns @@ -374,7 +287,7 @@ pile parcours(précédent, s, t) ::: -# Algorithme de Dijkstra +# Algorithme de Dijkstra (1 à 5) ::: columns @@ -395,7 +308,7 @@ pile parcours(précédent, s, t) ::: -# Algorithme de Dijkstra +# Algorithme de Dijkstra (1 à 5) ::: columns @@ -416,7 +329,7 @@ pile parcours(précédent, s, t) ::: -# Algorithme de Dijkstra +# Algorithme de Dijkstra (1 à 5) ::: columns @@ -438,7 +351,7 @@ pile parcours(précédent, s, t) ::: -# Algorithme de Dijkstra +# Algorithme de Dijkstra (1 à 5) ::: columns @@ -459,7 +372,7 @@ pile parcours(précédent, s, t) ::: -# Algorithme de Dijkstra +# Algorithme de Dijkstra (1 à 5) ::: columns @@ -480,7 +393,7 @@ pile parcours(précédent, s, t) ::: -# Algorithme de Dijkstra +# Algorithme de Dijkstra (1 à 5) ::: columns @@ -500,6 +413,106 @@ pile parcours(précédent, s, t) ::: +# Algorithme de Dijkstra + +## Idée générale + +* On assigne à chaque noeud une distance $0$ pour $s$, $\infty$ pour les autres. +* Tous les noeuds sont marqués non-visités. +* Depuis du noeud courant, on suit chaque arête du noeud vers un sommet non visité et on calcule le poids du chemin à chaque voisin et on met à jour sa distance si elle est plus petite que la distance du noeud. +* Quand tous les voisins du noeud courant ont été visités, le noeud est mis à visité (il ne sera plus jamais visité). +* Continuer avec le noeud à la distance la plus faible. +* L'algorithme est terminé losrque le noeud de destination est marqué comme visité, ou qu'on a plus de noeuds qu'on peut visiter et que leur distance est infinie. + +# Algorithme de Dijkstra + +## Pseudo-code (5min, matrix) + +\footnotesize + +. . . + +```C +tab dijkstra(graph, s, t) + pour chaque v dans graphe + distance[v] = infini + q = ajouter(q, v) + distance[s] = 0 + tant que non_vide(q) + // sélection de u t.q. la distance dans q est min + u = min(q, distance) + si u == t // on a atteint la cible + retourne distance + q = remove(q, u) + // voisin de u encore dans q + pour chaque v dans voisinage(u, q) + // on met à jour la distance du voisin en passant par u + n_distance = distance[u] + w(u, v) + si n_distance < distance[v] + distance[v] = n_distance + retourne distance +``` + +# Algorithme de Dijkstra + +* Cet algorithme, nous donne le plus court chemin mais... +* ne nous donne pas le chemin! + +## Comment modifier l'algorithme pour avoir le chemin? + +. . . + +* Pour chaque nouveau noeud à visiter, il suffit d'enregistrer d'où on est venu! +* On a besoin d'un tableau `précédent`. + +## Modifier le pseudo-code ci-dessus pour ce faire (3min matrix) + +# Algorithme de Dijkstra + +\footnotesize + +```C +tab, tab dijkstra(graph, s, t) + pour chaque v dans graphe + distance[v] = infini + précédent[v] = indéfini + q = ajouter(q, v) + distance[s] = 0 + tant que non_vide(q) + // sélection de u t.q. la distance dans q est min + u = min(q, distance) + si u == t + retourne distance + q = remove(q, u) + // voisin de u encore dans q + pour chaque v dans voisinage(u, q) + n_distance = distance[u] + w(u, v) + si n_distance < distance[v] + distance[v] = n_distance + précédent[v] = u + retourne distance, précédent +``` + +# Algorithme de Dijkstra + +## Comment reconstruire un chemin ? + +. . . + +```C +pile parcours(précédent, s, t) + sommets = vide + u = t + // on a atteint t ou on ne connait pas de chemin + si u != s && précédent[u] != indéfini + tant que vrai + sommets = empiler(sommets, u) + u = précédent[u] + si u == s // la source est atteinte + retourne sommets + retourne sommets +``` + # Algorithme de Dijkstra amélioré ## On peut améliorer l'algorithme