Vous êtes sur la page 1sur 2

Algorithmique et Programmation

Projet : Algorithme de Johnson

Ecole normale supérieure


Département d’informatique
td-algo@di.ens.fr ∗
2014-2015

Soit G = (V, E, w) un graphe orienté dont les arcs ont des poids w(·), des réels qui peuvent être
positifs ou négatifs. On notera u ∼ v pour (u, v) ∈ E. On suppose que G ne contient aucun cycle
Pn−1
s1 , . . . , sk−1 , sk = s1 , ∀i si ∼ si+1 dont le poids total i=1 w(si , si+1 ) soit strictement négatif. On
cherche à calculer le plus court chemin dans G entre tout couple (s, t) de sommets :
(k−1 )
X
δ(s, t) = min w(si , si+1 ) | s1 = s, sk = t, ∀i si ∼ si+1 .
i=1

Par convention ce minimum est +∞ s’il n’y a aucun chemin de s à t, et est 0 si s = t.


Une solution naı̈ve serait d’utiliser n fois l’algorithme de Bellman-Ford, une fois à partir de chaque
sommet.
1: Entrée : graphe H orienté avec poids p positifs ou négatifs, sommet s
2: Sortie : pour chaque u, longueur δ(u) du plus court chemin de s à u
3: function Bellman-Ford(H, p, s)
4: for all i de 1 à n − 1 do
5: for all arc u ∼ v do
6: δ(v) ← min(δ(v), δ(u) + p(u, v))
7: end for
8: end for
9: end function
L’astuce de l’algorithme de Johnson consiste, pour gagner du temps, à n’utiliser qu’une seule fois
l’algorithme de Bellman–Ford (en O(mn)), puis n fois l’algorithme de Dijkstra, plus efficace.
1: Entrée : graphe H orienté avec poids p positifs, sommet s
2: Sortie : pour chaque u, longueur δ(u) du plus court chemin de s à u
3: function Dijkstra(H, p, s)
4: δ(s) ← 0 et S ← {s}.
5: while S 6= VH do
6: choisir u ∈ VH \ S tel que minx∈S,x∼s(δ(x) + p(x, u)) soit minimum.
7: δ(u) ← minx∈S,x∼s(δ(x) + p(x, u)) et S ← S ∪ {u}
8: end while
9: return δ
10: end function
L’algorithme de Dijkstra est implémenté avec une file de priorité K contenant les sommets de VH \ S
avec les clés K(u) = minx∈S,x∼s(δ(x) + p(x, u)). Ici, on vous demandera de coder K avec un tas binaire
(voir [1, §6]).

1 Algorithme de Johnson
L’idée de l’algorithme de Johnson (voir [1, §26.3]) est de se réduire à un graphe dont les poids sont
tous positifs, puis sur ce nouveau graphe de faire appel n fois à l’algorithme de Dijkstra, une fois à partir
de chaque sommet. La réduction utilise l’algorithme de Bellman-Ford pour calculer une certaine valeur
δ(u) pour chaque sommet u, puis définit le nouveau poids wG (u, v) = w(u, v) + δ(u) − δ(v).
1: Entrée : graphe G orienté avec poids p positifs ou négatifs
∗ Révisé par Claire Mathieu 9/2013.

1
2: Sortie : pour chaque u, v, longueur δf (u, v) du plus court chemin de u à v
3: function Johnson(G, w)
4: Créer (H, wH ) : VH = VG ∪ {u0 }, (EH , wH ) = (EG , wG ) ∪ {(u0 , u)∀u, avec poids 0}
5: δ(·) ← BellmanFord(H, wH , u0 )
6: Créer wG : pour tout arc (u, v) de EG , wG (u, v) ← w(u, v) + δ(u) − δ(v)
7: for all u ∈ VG do
8: δu (·) ← Dijkstra(G, wG , u)
9: end for
10: for all arc (u, v) de G do
11: δf (u, v) ← δu (v) + δ(v) − δ(u)
12: end for
13: end function
La correction de l’algorithme de Johnson repose sur la propriété suivante remarquable de wG : ses
arêtes sont toutes de poids positifs.

2 Travail demandé
Vous écrirez une fonction qui calcule les plus cours chemins entre tout couple de sommets par l’algo-
rithme de Johnson.
L’argument de la fonction sera un graphe de taille arbitraire sous forme de listes d’adjacence, les
poids des arcs, de type int, ainsi qu’un sommet s. La sortie sur écran sera, pour chaque t ∈ S, la liste
ordonnée des sommets formant un chemin de poids minimum entre s et t ainsi que son poids, ou +∞ si
t n’est pas accessible depuis s. Votre fonction utilisera la structure de données des tas binaires que vous
devrez également programmer. Chaque fonction et procédure devra être testée sur des exemples.
Ainsi, votre travail se décompose en les étapes suivantes.
1. Implementation d’une fonction qui prend en entrée deux entiers n et m ≤ n(n − 1)/2] et donne en
sortie un graphe aléatoire orienté à n sommets et m arêtes donné sous forme de listes d’adjacence.
2. Implémentation de la variante de l’algorithme de Bellman-Ford qui retourne un message d’erreur
si le graphe possède un cycle de poids total négatif. Tests.
3. Implémentation naı̈ve de l’algorithme de Dijkstra. Tests sur des petits graphes, et sur des graphes
aléatoires dont les arêtes ont des poids aléatoires uniformes entre 0 et 1000.
4. Implémentation d’une file de priorité avec un tas binaire (tableau). Implémentation de l’algorithme
de Dijkstra avec une file de priorité. Tests.
5. Implémentation de l’algorithme de Johnson. Tests sur des petits graphes, et sur des graphes aléa-
toires dont les arêtes ont des poids aléatoires uniformes entre −500 et 1000.
6. Enfin, vous ferez quelques expériences en variant |A| et |S| pour vérifier expérimentalement le coût
théorique (attention au coût de la génération du graphe et de la sortie sur écran).

Références
[1] Charles E Leiserson, Ronald L Rivest, Clifford Stein, and Thomas H Cormen. Introduction to algo-
rithms. The MIT press, 2001.