Bruteforce & backtracking pour résoudre des problèmes NP-complets
Temps de lecture30 minEn bref
Résumé de l’article
Dans cet article, nous vous présentons une approche pour résoudre le problème du voyageur de commerce (TSP), ou plus généralement des problèmes NP-complets. Cette approche repose sur une recherche exhaustive des solutions possibles, avec une stratégie d’accélération appelée “backtracking” (backtracking).
À retenir
-
Une approche par bruteforce (exhaustive) peut être utilisée pour résoudre un problème NP-complet.
-
Pour le TSP, elle construit un arbre où chaque branche représente une solution possible.
-
La complexité de résolution du TSP avec un algorithme bruteforce est $O(n!)$.
-
Le backtracking est une optimisation qui permet d’arrêter l’exploration des branches prématurément.
-
La méthode “branch-and-bound” est une autre optimisation possible.
Contenu de l’article
1 — Vidéo
Veuillez consulter la vidéo ci-dessous (en anglais, affichez les sous-titres si besoin). Nous fournissons également une traduction du contenu de la vidéo juste après, si vous préférez.
Certaines “codes” apparaissent dans cette vidéo. Veuillez garder à l’esprit que ce sont des pseudo-codes, c’est-à-dire qu’ils ne sont pas écrits dans un langage de programmation réel. Ça ressemble à du Python, mais ça n’est pas du Python !
Leur but est simplement de décrire les algorithmes sans se soucier des détails de la syntaxe d’un langage de programmation particulier. Vous devrez donc effectuer un peu de travail pour les rendre pleinement fonctionnels en Python si vous souhaitez les utiliser dans vos programmes.
Pour aller plus loin
2 — L’algorithme branch-and-bound
Un troisième algorithme pour résoudre exactement le TSP est l’algorithme branch-and-bound.
L’algorithme branch-and-bound explore l’arbre des possibilités (dans le cas du voyageur de commerce, l’arbre des chemins possibles). Pour ce faire, il utilise un algorithme de type BFS. À chaque sommet rencontré, il tente d’estimer un intervalle (aussi étroit que possible) estimant la longueur d’un chemin plus court obtenu à partir de la branche de l’arbre où il se trouve actuellement.
Pour obtenir ces intervalles, plusieurs techniques existent :
-
Pour obtenir une borne supérieure, il suffit d’utiliser un algorithme glouton, qui estime la longueur du chemin restant en allant toujours au sommet le plus proche. Cela donne un chemin qui n’est pas nécessairement optimal, mais dont la longueur ne peut être que supérieure à celle d’un chemin plus court.
-
Pour obtenir une borne inférieure, on peut par exemple compter le nombre de sommets non encore visités (appelons ce nombre $k$). Dans le meilleur des cas, ils peuvent être visités en passant par les $k$ arêtes de poids les plus faibles. La somme de ces $k$ poids donne la borne inférieure. Cette réduction est souvent grossière, et il est préférable de chercher la plus fine.
Lorsque l’algorithme a déterminé plusieurs intervalles (un par branche à explorer), il peut les comparer entre eux. Dans le cas de la recherche d’un chemin de longueur minimale, si l’intervalle d’une branche $b_1$ a pour borne supérieure une valeur inférieure à la borne inférieure d’un intervalle d’une autre branche $b_2$, alors le sous-arbre correspondant à $b_2$ est éliminé. En effet, il n’y a aucun intérêt à explorer le sous-arbre $b_2$ sachant que la meilleure solution trouvée sera de toute façon moins intéressante que les pires en continuant sur la branche $b_1$.
2.1 — Complexité
La complexité de l’algorithme est dans le pire des cas la même qu’une recherche exhaustive (si l’estimation des limites ne coûte pas trop cher). C’est par exemple le cas avec un graphe complet dans lequel toutes les arêtes ont le même poids.
En pratique, avoir une bonne précision dans l’estimation des intervalles peut faire gagner beaucoup de temps. Un cas optimal est celui d’une complexité linéaire.
2.2 — Compromis précision-performance
Comme pour tous les algorithmes approximatifs, l’estimation des intervalles pose le problème du compromis précision-performance. En effet, plus l’intervalle est étroit, plus il permettra d’élaguer des parties de l’arbre. Cependant, si son estimation nécessite un calcul coûteux, cela a un impact sur la complexité totale.
Il est donc nécessaire de trouver des estimations des bornes des intervalles offrant un bon compromis entre temps de calcul et précision.
Pour aller encore plus loin
-
Cet algorithme résout le TSP en $O(n^2 \cdot 2^n)$.
-
Un outil rapide pour résoudre le TSP et d’autres problèmes d’optimisation.
-
Traveling Salesman Problem using Branch And Bound.
Une implémentation possible en Java/C++ de l’algorithme.

