diff --git a/df.md b/df.md index 196b8ea75952b5bab929c4a1d9a3dabf364bcb35..2d9511f5d61ee2b0134c73c117e9d27a61fb0527 100644 --- a/df.md +++ b/df.md @@ -62,9 +62,10 @@ Le pseudo-code est donné par void dijkstra(graph g, int src, int num, int dist[num], int prev[num]) { dist[src] = 0; // all other distances are INT_MAX prev[src] = -1; // previous node is undefined + queue_init(q, (source, 0)); - !queue_is_empty(q) { + while (!queue_is_empty(q)) { p = queue_pop(q); for v in the neighborhood of p { d_new = dist[v] + ditsance(p, v); @@ -84,6 +85,177 @@ est dans le tableau `dist`. Le parcours entre `src` et un sommet `v`, est obtenu à l'aide du tableau `prev` en suivant les indices en partant de `prev[v]`. +# L'algorithme de Floyd(--Warshall) + +L'algorithme de Floyd (ou Floyd--Warshal) est un algorithme qui sert +à trouver les plus courts chemins entre toute paire de sommets d'un graphe. + +Dans cette section nous allons d'abord décrire l'algorithme puis voir son implémentation. + +## Description de l'algorithme + +Considérons un graphe avec $N$ sommets, numérotés de 0 à $N-1$. +Soit la fonction `shortest_path(i,j,k)` la fonction retournant le plus court +chemin entre le sommet `i` et le sommet `j` en utilisant uniquement les sommets `0, ..., k-1` comme sommets intermédiaires. En supposant +cette fonction connue, nous voulons trouver le plus cours chemin en utilisant +les sommet `0` à `N-1`. Pour chaque `shortest_path(i, j, k)` nous avons deux possibilités: + +1. le chemin ne passe pas par `k-1` (il ne passe que par les sommets `0` à `k-2`). +2. le chemin passe par `k-1`: d'abord de `i` à `k-1` puis de `k-1` à `j`. + +Dans le premier cas, nous savons que le plus court chemin est défini par `shortest_path(i,j,k-1)`. +Dans ce second cas, le chemin serait la réunion des chemins de `i` +à `k`, puis de `k` à `j`. Ce chemin serait donc la somme des chemins +`shortest_path(i, k, k-1)` et `shortest_path(k,j,k-1)`. + +De la définition de la fonction `shortest_path(i,j,k)`, on peut déduire que +`shortest_path(i,j,0)` est donné par + +```C +shortest_path(i,j,0)=w(i,j), +``` + +où `w(i,j)` est le poids de l'arrête entre les sommets `i` et `j`. + +Finalement, on peut définir le plus cours chemin récursivement + +```C +shortest_path(i,j,k) = min(shortest_path(i,j,k-1), + shortest_path(i,k,k-1) + shortest_path(k,j,k-1)). +``` + +## Implémentation de l'algorithme de Floyd + +L'algorithme de Floyd s'implémente à l'aide de la matrice d'adjacence. +Il est décrit en pseudo-code comme + +```C +void floyd_warshall(int num, int dist[num][num], int next[num][num]) { + int dist[num][num]; // init with INT_MAX + int next[num][num]; // init with -1 + + for each edge (i, j) { + dist[i][j] = w(i, j) // The weight of the edge (i, j) + next[i][j] = j + } + for each vertex j { + dist[j][j] = 0 + next[j][j] = j + } + for (int k = 0; k < num; ++k) { // standard Floyd-Warshall implementation + for (int i = 0; i < num; ++i) { + for (int j = 0; j < num; ++j) { + if (dist[i][j] > dist[i][k] + dist[k][j]) { + dist[i][j] = dist[i][k] + dist[k][j] + next[i][j] = next[i][k] + } + } + } + } +} +``` + +Pour retrouver le chemin il faut simplement suivre les indices dans +la matrice `next` de la façon suivante + +```C +void get_path(int i, int j, int num, int next[num][num], vector *path) { + if next[i][j] is negative { + return + } + vector_push(path, i); + while (i != j) { + i = next[i][j]; + vector_push(path, i); + } +} +``` + +# Tests + +Afin de tester le code, vérifier que si vous chercher les temps de parcours entre +les villes: + +``` +Geneve; Sion +Andermatt; Coire +Schaffouse; Lausanne +Lucerne; Delemont +Coire; Geneve +Bale; Bellinzone +Andermatt; Geneve +Lausanne; Delemont +Neuchatel; Bellinzone +Bellinzone; Geneve +Sion; Bale +Lausanne; Geneve +St.-Moritz; Geneve +Sion; Schaffouse +St.-Gall; Lausanne +Neuchatel; Andermatt +Sion; Neuchatel +Bale; Geneve +Geneve; Bale +Berne; Bellinzone +``` + +on obtient: + +``` +101 100 188 107 271 205 263 89 257 316 +190 34 387 255 212 227 107 157 157 215 +``` + +Puis les chemins entre les villes + +``` +Geneve; Sion +Andermatt; Coire +Schaffouse; Lausanne +Lucerne; Delemont +Coire; Geneve +Bale; Bellinzone +Andermatt; Geneve +LausanneDelemont +Neuchatel; Bellinzone +Bellinzone; Geneve +Sion; Bale +Lausanne; Geneve +St.-Moritz; Geneve +Sion; Schaffouse +St.-Gall; Lausanne +Neuchatel; Andermatt +Sion; Neuchatel +Bale; Geneve +Geneve; Bale +Berne; Bellinzone +``` + +sont donnés par + +``` +[Geneve:Lausanne:Sion] +[Andermatt:Coire] +[Schaffouse:Zurich:Berne:Lausanne] +[Lucerne:Bale:Delemont] +[Coire:Zurich:Berne:Lausanne:Geneve] +[Bale:Lucerne:Bellinzone] +[Andermatt:Sion:Lausanne:Geneve] +[Lausanne:Neuchatel:Delemont] +[Neuchatel:Berne:Lucerne:Bellinzone] +[Bellinzone:Lucerne:Berne:Lausanne:Geneve] +[Sion:Lausanne:Neuchatel:Delemont:Bale] +[Lausanne:Geneve] +[St.-Moritz:Coire:Zurich:Berne:Lausanne:Geneve] +[Sion:Lausanne:Berne:Zurich:Schaffouse] +[St.-Gall:Zurich:Berne:Lausanne] +[Neuchatel:Berne:Lucerne:Andermatt] +[Sion:Lausanne:Neuchatel] +[Bale:Delemont:Neuchatel:Lausanne:Geneve] +[Geneve:Lausanne:Neuchatel:Delemont:Bale] +[Berne:Lucerne:Bellinzone] +``` + [^1]: Cela veut dire qu'il n'y a pas de chemin entre le sommet de départ et celui d'arrivée. \ No newline at end of file