informatique (tronc commun des prépas scientifiques) · Chapitre 18 · Exercice de TD
Floyd-Warshall — toutes les distances d'un graphe en trois lignes
La programmation dynamique · niveau 3 (difficile)
Énoncé
(a) Soit un graphe pondéré à sommets. Définir comme la longueur du plus court chemin de à dont les sommets intermédiaires appartiennent tous à l'ensemble . Exprimer la récurrence. (b) Implémenter l'algorithme Floyd-Warshall en Python et vérifier son comportement sur le graphe piège comportant un arc de poids négatif vu au chapitre 14 : , et (la distance doit valoir ). (c) Comparer la complexité avec la répétition de l'algorithme de Dijkstra.
Corrigé
(a) Le plus court chemin de à passant par les sommets intermédiaires inférieurs à soit passe par le sommet (et se décompose en ), soit ne passe pas par . La récurrence s'écrit : avec initialisée à la valeur du poids de l'arc de à (ou en l'absence d'arc). (b)
def floyd_warshall(M: list) -> list:
n = len(M)
for k in range(n):
for i in range(n):
for j in range(n):
if M[i][k] + M[k][j] < M[i][j]:
M[i][j] = M[i][k] + M[k][j]
return M
INF = float("inf")
# Sommets s, a, b indexés par 0, 1, 2
M = [[0, 2, 3],
[INF, 0, INF],
[INF, -2, 0]]
floyd_warshall(M)
assert M[0][1] == 1 # s -> b -> a : poids 3 - 2 = 1
L'algorithme de Floyd-Warshall gère correctement les arcs de poids négatifs (contrairement à Dijkstra) tant qu'il n'y a pas de cycle de poids négatif. (c) Floyd-Warshall s'exécute en en temps et nécessite une simple matrice en espace. Dijkstra exécuté fois prend en temps avec une implémentation par tableau simple, mais peut descendre à avec un tas. Floyd-Warshall est donc préférable sur les graphes denses ou en présence d'arcs négatifs, tandis que Dijkstra répété est plus rapide sur les grands graphes creux sans arcs négatifs.