2-750-04 Algorithmique et programmation en gestion Leçon 6 Les algorithmes énumératifs Retour-arrière («Backtracking»)
Qu’est-ce qu’un problème énumératif? C’est un problème où la question à résoudre est: Compter de combien de façons… Lister toutes les façons de … Une certaine exaustivité est exigée Exemple: Le problème de la monnaie Trouver toutes les façons de payer un certain montant Problème des 8 reines…
Découvrir le phénomène des boucles imbriquées
Comprendre le concept de profondeur d'une imbrication de boucle Une boucle à l’intérieur de laquelle il n’y a aucune autre boucle est de profondeur 1 Une boucle contenant une boucle intérieure de profondeur 1 est de profondeur 2 De manière générale, une imbrication de boucles est de profondeur n, si la boucle extérieure contient une boucle imbriquée de profondeur n-1 Une structure d’imbrications de boucles de profondeur n, dont chaque boucle tourne n fois, fait en sorte que l’instruction la plus imbriquée est exécutée nn fois
Découvrir le phénomène des boucles imbriquées La structure algorithmique suivante provoque une imbrication de boucles de profondeur p Algorithme bouclesImbriquées(n,i) Si i<=p alors Pour j Allant de 1 à n bouclesImbriquées(n,i+1) Fin Pour FinSi Cet algorithme comporte 2 paramètres Le paramètre i sert à contrôler les appels et donc la profondeur Le paramètre n contrôle le nombre d’appels à un niveau donné
Découvrir le phénomène des boucles imbriquées L’effet combiné peut être illustré comme suit Pour j Allant de1 à n . . . Pour j' Allant de 1 à n Pour j'' Allant de 1 à n Imbrication(n, p) Fin Pour FinPour
Découvrir en quoi consiste le backtracking
Découvrir en quoi consiste le backtracking Nous avons à faire ici à n boucles imbriquées, chaque boucle comptant k exécutions L’algorithme se présente donc comme suit Algorithme tousLesMots(i,k,n) Si i > n Alors Écrire mot Sinon Pour j Allant de 1 à k mot[i] ← jème lettre tousLesMots(i+1,k,n) FinPour FinSi
Découvrir en quoi consiste le backtracking Lorsque la boucle au niveau i se termine, la boucle de niveau i-1 s’exécute une fois Cela fait exécuter de nouveau la boucle de niveau i k fois C’est l’approche dite par « backtracking » ou retour arrière L’effet retour arrière correspond au fait suivant Ayant épuisée tous les choix de la position i, l'algorithme Revient sur la position i-1 Change le choix de cette position Repart fabriquer toutes les solutions dont les i-1 premiers choix restent les mêmes Dans notre exemple, pour utiliser effectivement les caractères d’un alphabet, on utilise un tableau stockant les lettres de cet alphabet Supposons un tableau alphabet tel que alphabet[i] soit le ième caractère de l’alphabet Alors mot[i] ← jème lettre devient mot[i] ← alphabet[j]
Découvrir en quoi consiste le backtracking sélectif
Découvrir en quoi consiste le backtracking sélectif On doit modifier l’algorithme précédent comme suit Algorithme tousLesMotsSansRépétition(i,k,n) Si i > n Alors Écrire mot Sinon Pour j Allant de 1 à k Si alphabet[j] ne fait pas partie de mot[1],…mot[i-1] Alors mot[i] ← alphabet[j] tousLesMotsSansRépétition(i+1,k,n) FinSi FinPour
Découvrir en quoi consiste le backtracking sélectif On arrive à la structure de programmation suivante : L’algorithme comporte une boucle La boucle comporte un appel récursif L’appel récursif est dans la boucle L’appel récursif est conditionnel On nomme cette structure algorithmique par le nom de « Backtracking sélectif» ou « Retour arrière sélectif » Dans notre exemple, lorsque la longueur des mots correspond au nombre de caractère de l’alphabet, on parle alors de permutation
Comprendre le fonctionnement général d'un algorithme de backtracking
Comprendre le fonctionnement général d'un algorithme de backtracking Description Algorithme générique de backtracking. L'algorithme utilise 5 fonctions utilitaires : essayerChoix() succesSolution() solutionPartielleOK() retirerChoix() traitementSolution() Variables sol (...) : structure de la solution courante n (entier) : nombre maximum de niveaux niveau (entier) : niveau courant de la solution partielle choix (entier) : choix à tenter au niveau courant k (entier) : indice pour les essais des niveaux suivants Logique prolongerSolution (sol, n, niveau, choix) essayerChoix(sol, niveau, choix) Si succesSolution(sol, n, niveau) alors traitementSolution(sol) Sinon si solutionPartielleOK(sol, niveau) alors Pour k = 1 à n faire prolongerSolution(sol, n, niveau+1, k) Fin-pour Fin-si retirerChoix(sol, niveau, choix)
Construire et défaire les solutions partielles Pour qu'une approche par backtracking fonctionne correctement, il faut que la structure de données utilisée permette L'ajout rapide d'une solution partielle pour le prochain niveau à tenter Le retrait rapide d'une solution partielle une fois la tentative terminée Les variables niveau et choix permettent de contrôler quelle est la solution partielle à tenter (choix) et où placer cette solution partielle (niveau)
Programmer une solution avec backtracking en Java void essayerChoix(... sol, int niveau, int choix) { ... } boolean succesSolution(... sol, int n, int niveau) { ... } void traitementSolution(... sol) { ... } boolean solutionPartielleOK(... sol, int niveau) { ... } void retirerChoix(... sol, int niveau, int choix) { ... } void prolongerSolution (... sol, int n, int niveau, int choix) { essayerChoix(sol, niveau, choix); if (succesSolution(sol, n, niveau)) { traitementSolution(sol); } else if (solutionPartielleOK(sol, niveau)) { for (int k=1; k <= n; k++) { prolongerSolution(sol, n, niveau+1, k); } retirerChoix(sol, niveau, choix);
Programmer une solution avec backtracking en Java Ce n'est pas plus compliquer que de développer une solution avec récursivité On doit déterminer une structure appropriée, puis l'utiliser de façon raisonnable avec les méthodes de l'algorithme générique On ajustera les méthodes et paramètres selon cette structure de données.