TD4 Correction
TD4 Correction
TD4 Correction
1. Utilisez les algorithmes du cours pour déterminer, pour chacun des graphes ci-dessous, une arborescence
de plus courts chemins du sommet s à tous les autres.
am
1 fm
6@ 1 2 @ amXXX
@ 2 XX3X
m
@
R
7 2 e 2 6@
@ −2
XXX
1 3
@ 1 z
X
m
@ @ @ −5 e
sm 3 - bm 8 - gm 2 - hm sm cm
? @
1
@
R R
@ R
@
)
@−2 −1
@ I
@ @
3
@ 6
@4 2 7 6
1 @
m 2 m
@ @ 2 - 5 @
bm
@ R
@ 4 - m
@
3 @
2 1 @ 3 d
cm 3 - dm
@R
@ ? @ @ @
s
1m −2 4m 7m
@
R @
R
2
@ 2 −5 @ −2 4
@ @
3m 2 - 6m
R ?
@ R ?
@
2
• Il faut et il suffit de vérifier les choses suivantes :
— T [s] = 0
— ∀v ∈ S − {s}, T [v] = min{u|u→v} {T [u] + w(u → v)}
— ∀v ∈ S, si v n’est pas accessible depuis s, alors T [t] = ∞
— les sommets accessibles depuis s sont encore accessibles depuis s dans le graphe G0 ou l’on ne
garde que les arêtes u → v vérifiant T [v] + w(u → v)
Tout cela est bien vérifiable en temps linéaire : les deux premières conditions se vérifient sommet par
sommet et arête par arête, en marquant les arêtes qui vérifient le min dans la deuxième condition.
Puis on effectue un parcours en partant de s pour identifier les sommets accessibles, afin de vérifier
la troisième conditions, et enfin un autre parcours en ne passant que par les arêtes marquées à la
première étape.
Montrons maintenant que ces conditions sont nécessaires et suffisantes.
D’abord, il est évident que si T contient les distances à s de chaque sommet, alors T respecte les
différentes propriétés.
Supposons maintenant que T respecte ces propriétés. Notons d(v) la distance de s à v pour tout
v ∈ S.
On va montrer par des récurrences sur des valeurs définies différemment que T [v] 6 d(v) pour tout
v et que T [v] > d(v) pour tout v.
Lemme 1 : ∀v ∈ S, T [v] 6 d(v).
Pour v non-accessible depuis s, c’est évident car d(v) = ∞.
Soit v un sommet accessible depuis s, i.e d(v) < ∞, et notons l la longueur en nombre d’arête d’un
plus court chemin C entre s et v. On va montrer par récurrence sur l que le lemme est vrai.
Si l = 0, alors v = s et donc T [v] = 0 = d(v).
Si l > 0, supposons le lemme vrai pour l − 1. Considérons la dernière arête du plus court chemin C
de s à v de longueur l ; notons-la u → v. Alors le chemin C auquel on enlève sa dernière arête est
un plus court chemin vers u (sinon C ne serait pas un plus court chemin vers v) et prend l − 1 arête,
donc par hypothèse de récurrence, T [u] 6 d(u).
Le lemme 1 est donc bien vérifié pour tout sommet de G.
Lemme 2 : ∀v ∈ S, T [v] > d(v).
Si v est non-accessible depuis s, alors par la troisième condition, T [v] = ∞ donc le lemme est vérifié.
Soit maintenant v un sommet accessible dans G à partir de s, donc également dans G0 par la qua-
trième condition. Notons l la longueur en arêtes du plus court chemin entre s et V dans G0 .
Si l = 0, alors v = s et donc T [v] = 0 = d(v).
Si l > 0, supposons le lemme vrai pour l − 1. Considérons la dernière arête du plus court chemin
C 0 de s à v dans G0 de longueur l − 1 ; notons-la u → v. Alors le chemin C 0 auquel on enlève sa
dernière arête est un plus court chemin dans G0 de s vers u et prend l − 1 arêtes, donc par hypothèse
de récurrence, T [u] > d(u).
Or comme u → v est dans G0 , on sait que cette arête vérifie T [v] = T [u] + w(u → v). De plus,
on sait que comme tout chemin entre s et u auquel on ajoute u → v est un chemin de s vers v,
d(v) 6 d(u)+w(u → v). On en déduit qu’on a bien T [v] = T [u]+w(u → v) > d(u)+w(u → v) > d(v).
Ainsi le lemme 2 est bien vérifié pour tout sommet de G.
On a donc bien prouvé que pour tout v ∈ S, T [v] = d(v).
Remarque : la quatrième condition est bien strictement nécessaire à moins qu’on sache que le graphe
G ne contient aucun cycle de poids nul. Exo en rab : Modifier cet algorithme pour construire une
arborescence des plus-courts chemins issus de s, toujours ne temps linéaire.
6. Proposer un algorithme qui ramène le calcul des plus courts chemins depuis une source pour les graphes
à valuation dans IN ∗ , à un parcours en largeur. Cet algorithme est-il compétitif face à l’algorithme de
Dijkstra ?
• En utilisant le fait que tous les poids sont positifs et multiples de 1, on peut transformer le graphe
de façon à ce qu’un parcours en largeur suffise à déterminer les distances. Pour cela, on modifie les
arêtes ainsi : si l’arête uv est de poids k, on ajoute k − 1 sommets entre u et v, placés en ligne. Ainsi,
la distance entre deux sommets est figurée par k arêtes de poids 1 plutôt qu’une arête de poids k.
3
On peut alors vérifier aisément qu’un plus court chemin dans ce graphe modifié est de même longueur
qu’un plus court chemin dans le graphe original, puisque si il passe par une des w(uv) arêtes de poids
1 entre u et v, il passe par toutes. Il y a donc équivalence entre les plus courts chemins dans le graphe
original G et le nouveau graphe G0 . P
La taille de ce nouveau graphe est est θ(|S|+|A|+ a∈A w(a)), et le parcours qui permet de déterminer
les plus courts chemins dans G0 est linéaire en cette taille.
Si les coûts des arcs peuvent être arbitrairement grands, cette technique ne sera donc pas compétitive.
En revanche, si les poids sont petits, elle peut être rentable. Si on prend la version de l’algorithme de
Dijkstra en θ(m log m, on obtient que c’est intéressant dans le cas où le coût moyen des arêtes est
o(log m).
Remarque : On utilise ici la double propriété de N : les nombres sont positifs et tous multiples de 1.
On ne peut appliquer cette technique ni dans Z ni dans R+ .
Rappeler l’algorithme de Floyd-Roy-Warshall et l’utiliser pour calculer la matrice des PCC de tout
sommet à tout sommet. Observer comment le plus court chemin de 3 à 2 a été trouvé.
• Pour le rappel de l’algorithme, se reporter au cours.
Le graphe étudié a 5 sommets, on va donc calculer 6 matrices qui correspondent à la matrice de
départ (k = 0) et aux étapes k = 1 à 5 de l’algorithme.
Le matrice de départ correspond à la matrice donnée dans l’énoncé, sauf qu’on remplace tous les
coefficients diagonaux par des 0, puisqu’on n’a pas besoin d’arêtes pour savoir que la distance d’un
sommet avec lui-même est nulle.
0 1 ∞ 0 ∞
∞ 0 2 1 3
Matrice de départ : 4 ∞ 0 1 3
3 ∞ 1 0 1
1 4 ∞ 0 0
0 1 ∞ 0 ∞
∞ 0 2 1 3
Étape 1 : 4 5 0 1 3
3 4 1 0 1
1 2 ∞ 0 0
0 1 3 0 4
∞ 0 2 1 3
Étape 2 : 4 5 0 1 3
3 4 1 0 1
1 2 4 0 0
0 1 3 0 4
6 0 2 1 3
Étape 3 : 4 5 0 1 3
3 4 1 0 1
1 2 4 0 0
0 1 1 0 1
4 0 2 1 2
Étape 4 : 4 5 0 1 2
3 4 1 0 1
1 2 1 0 0
4
0 1 1 0 1
3 0 2 1 2
Étape 5 : 3 4 0 1 2
2 3 1 0 1
1 2 1 0 0
Le plus court chemin de 3 à 2 est de longueur 4, d’après cet algorithme. Il est mis à jour à l’étape 5
en additionnant 2 et 2, donc il est de la forme 3 →2 5 →2 2.
Or 3 → 5 est mis à jour à l’étape 4 en additionnant 1 et 1, donc le chemin est de la forme 3 →1
4 →1 5 →2 2, et comme ces 1 dont des coefficients de la matrice originale, les deux premières flèches
représentent des arêtes.
De même, 5 → 2 est mis à jour à l’étape 1 en additionnant 1 et 1, qui sont des coefficients originaux,
donc le chemin entre 5 et 2 est 5 →1 1 →1 2 et ces flèches sont des arêtes.
Ainsi, le plus court chemin entre 3 et 2 est le suivant :
3 →1 4 →1 5 →1 1 →1 2
faire n fois :
pour tous les sommets y faire
pour tout successeur z de y faire
si d[z] > d[y] + w(y,z)
alors d[z] <- d[y] + w(y,z)
pred[z] <- y
• Une deuxième distance d2 entre s et z peut avoir deux types de valeurs : soit l’avant-dernier sommet
y du deuxième plus court chemin est le même que celui du plus court chemin, et alors d2 (z) =
d2 (y) + w(y, z), soit l’avant-dernier sommet y est différent de celui du plus court chemin, et dans ce
cas d2 (z) = d(y) + w(y, z).
On met donc à jour les deux valeurs d et d2 à chaque étape en testant ces deux possibilités.
5
si d[z] > d[y] + w(y,z)
alors d[z] <- d[y] + w(y,z);
pred[z] <- y;
fin si;
si y = pred[z] et d2[z] > d2[y] + w(y,z)
alors d2[z] <- d2[y] + w(y,z);
fin si;
fin pour;
fin pour;
fin pour;
renvoyer d,d2;
(B) Les valuations de G sont supposées positives.
Complétez le code ci-dessous (Dijkstra) pour calculer les tableaux d et d2.
pour tout sommet t, d[t] <- infini
d[s] <- 0
E <- S
faire n fois :
soit y dans E tq d[y] minimise { d[w] | w dans E }
E <- E - { y }
pour tout successeur z de y faire
si d[z] > d[y] + w(y,z)
alors d[z] <- d[y] + w(y,z)
• Cette fois-ci, on va effectuer deux passages de Dijkstra successifs sur le graphe. Le premier calcule
les distance classiques, et le second les deuxièmes distances, en initialisant la valeur de d2 (z) au min
des d(y) + w(y, z) pour y un prédécesseur de z qui n’est pas son prédécesseur sur le plus court chemin
entre s et z.
L’algorithme fonctionnera car un deuxième plus court chemin a une forme très spécifique : si T est
l’arbre des plus courts chemins trouvé lors du premier passage de Dijkstra, alors :
— soit d2 (z) = d2 (y) + w(y, z) où y est le prédécesseur de z dans T , donc le deuxième pcc de s à z
est le deuxième pcc de s à y plus l’arête (y, z) qui est dans T ;
— soit d2 (z) = d(y) + w(y, z) où y n’est pas le prédécesseur de z dans T , et donc le deuxième pcc
de s à z est le pcc de s à y (inclu dans T ) plus l’arête (y, z), qui n’est pas dans T .
Dans tous les cas, un deuxième pcc contient toujours exactement une arête qui n’est pas dans T : si
il n’en contenait pas il serait un pcc, mais si il en contient une, toutes celles d’avant sont dans T
(cas 2) et toutes celles d’après sont aussi dans T (cas 1).
Donc on peut modifier la preuve habituelle de la correction de Dijkstra en faisant une récurrence sur
le nombre d’arêtes après l’arête hors de T dans le deuxième plus court chemin de s à v.
d <- tableau(n,infini);
d[s] <- 0;
pred[s] <- (n, indéfini);
E <- S;
pour k = 1 à n faire
soit y dans E tq d[y] minimise { d[w] | w dans E };
E <- E - { y };
pour tout successeur z de y faire
si d[z] > d[y] + w(y,z)
alors d[z] <- d[y] + w(y,z);
pred[z] <- y;
fin si;
fin pour;
fin pour;
6
d2 <- (n, infini);
pour tout y sommet faire
pour tout successeur z de y faire
si y != pred[z] alors d2[z] <- min(d2[z], d[y]+w(y,z));
fin pour;
fin pour;
E <- S;
pour k = 1 à n faire
soit y dans E tq d2[y] minimise { d[w] | w dans E };
E <- E - { y };
pour tout successeur z de y faire
si y = pred[z] alors d2[z] <- min(d2[z], d2[y] + w(y,z));
fin pour;
fin pour;
renvoyer d,d2;