Aller d'un point à un autre au moindre coût — et découvrir qu'une route de plus peut tout ralentir.
Un réseau : des carrefours reliés par des tronçons, chacun portant un coût — kilomètres, minutes, péage, consommation. Il faut aller d'un point à un autre en minimisant la somme. C'est sans doute le problème d'optimisation le plus exécuté au monde : chaque calcul d'itinéraire, chaque paquet routé sur Internet, chaque robot qui traverse un entrepôt le résout, des milliards de fois par jour.
Sa solution repose sur une propriété d'apparence anodine : tout sous-chemin d'un plus court chemin est lui-même un plus court chemin. Si le meilleur trajet de Paris à Rome passe par Lyon, alors sa portion Paris-Lyon est le meilleur trajet de Paris à Lyon — sinon on la remplacerait. Toute la famille des algorithmes découle de là. Les quatre premières planches les construisent ; la cinquième montre qu'ajouter une route à un réseau peut allonger le trajet de tout le monde.
L'algorithme de Dijkstra (1956) procède par vagues. Chaque sommet porte une étiquette provisoire — la meilleure distance connue jusqu'ici — et l'on répète une seule opération : prendre le sommet provisoire de plus petite étiquette, la déclarer définitive, et mettre à jour ses voisins. Le raisonnement qui justifie ce culot est simple : puisque tous les coûts sont positifs, aucun détour ne pourra jamais faire mieux qu'un chemin déjà plus long au départ.
Le contrôle des sous-chemins n'est pas décoratif : la page reprend le chemin trouvé, en extrait chaque portion, et vérifie que sa longueur est bien la distance optimale entre ses deux extrémités. C'est le principe d'optimalité de Bellman, vérifié case par case — et c'est lui qui autorise à ne jamais revenir sur une étiquette déclarée définitive.
Un coût peut être négatif : une étape qui rapporte, un tronçon subventionné, une conversion favorable. Dijkstra s'effondre alors, et pas discrètement — il rend une mauvaise réponse sans le signaler. La raison tient en une phrase : il fige une étiquette en pariant qu'aucun chemin plus long ne fera mieux ensuite, ce qui devient faux dès qu'un arc peut faire baisser le total.
Bellman-Ford renonce à ce pari : il relâche tous les arcs, n − 1 fois de suite. Après k passes, toutes les distances utilisant au plus k arcs sont exactes ; comme un plus court chemin sans circuit a au plus n − 1 arcs, on a fini. Et si une n-ième passe améliore encore quelque chose, c'est qu'il existe un circuit absorbant : le problème n'a plus de solution, on peut tourner en rond en gagnant à chaque tour.
Si l'on remplace chaque taux de change par moins son logarithme, un circuit absorbant devient exactement une suite de conversions qui ramène plus que la mise de départ. Bellman-Ford est donc, tel quel, un détecteur d'arbitrage.
Dijkstra explore dans toutes les directions à la fois : pour un trajet Paris-Rome, il visiterait Brest avant Milan. L'algorithme A* corrige ce gâchis en ajoutant à chaque étiquette une estimation h de ce qu'il reste à parcourir — ici la distance à vol d'oiseau — et en choisissant le sommet qui minimise d + h. Tant que l'estimation ne surestime jamais la distance réelle, le résultat reste exactement optimal, mais l'exploration se resserre en un fuseau autour de la ligne droite.
Le balayage montre le compromis en entier. À poids nul, A* est Dijkstra. À poids 1, l'estimation est admissible — la distance à vol d'oiseau ne peut pas dépasser la distance réelle — et l'on gagne beaucoup d'exploration sans rien perdre. Au-delà, on va plus vite encore mais l'on n'a plus aucune garantie : c'est le domaine des heuristiques gloutonnes, où l'on échange de l'exactitude contre du temps en connaissance de cause.
Quand il faut les distances entre tous les couples, relancer Dijkstra n fois marche, mais il existe plus élégant. Floyd et Warshall proposent une récurrence sur les sommets autorisés comme intermédiaires : notons Dk(i,j) la meilleure distance n'empruntant que les sommets 1…k comme relais. Alors
Dk(i,j) = min( Dk−1(i,j) , Dk−1(i,k) + Dk−1(k,j) )
— soit on ne passe pas par k, soit on y passe, et le chemin se coupe alors en deux morceaux qu'on connaît déjà. Trois boucles imbriquées, six lignes de code, et toute la matrice des distances.
Jusqu'ici les coûts étaient fixes. Sur une route réelle, ils dépendent du trafic : plus il y a de monde, plus c'est long. Chaque conducteur choisit alors son plus court chemin compte tenu de ce que font les autres, et le réseau se stabilise dans un équilibre de Wardrop : toutes les routes effectivement empruntées ont le même temps de parcours, sinon quelqu'un changerait.
Voici le réseau de Dietrich Braess (1968). Quatre mille conducteurs vont de S à T. Deux itinéraires symétriques : l'un commence par une route encombrable (x/100 minutes pour x véhicules) et finit par une route longue mais insensible au trafic (45 minutes) ; l'autre fait l'inverse. À l'équilibre, 2 000 conducteurs sur chaque, et 65 minutes pour tous. Ouvrons maintenant un raccourci instantané entre les deux itinéraires.
La courbe dit quelque chose de plus fort encore que le paradoxe lui-même : sur toute sa partie gauche, dégrader le raccourci améliore la situation de tout le monde. Le temps d'équilibre descend à mesure qu'on ralentit la nouvelle route, jusqu'à ce que plus personne ne l'emprunte et qu'on retrouve les 65 minutes du réseau d'origine. Fermer une voie peut fluidifier une ville — cela s'est vérifié à Séoul, à New York et à Stuttgart. L'explication tient en une phrase : chacun choisit son plus court chemin sans tenir compte du ralentissement qu'il inflige aux autres, et la somme de ces décisions rationnelles n'a aucune raison d'être bonne.