Premier Projet en OCaml Clément Chatelain et Vincent Gripon 4 avril 2007 1 Problème des tours de Hanoi 1.1 Présentation du problème Les tours de Hanoi est un jeu inventé par Edouard Lucas en 1883. Ce jeu est composé de trois tiges verticales et de disques de longueur décroissante (8 pour le jeu des tour de Hanoi, mais généralisable à un nombre quelconque). Au départ les disques sont enlés sur une première tige dans l'ordre de longueur décroissante. Le but du jeu est de transférer les disques sur l'une des deux autres tiges en déplaçant un disque à la fois et en plaçant toujours un disque sur un autres disque plus grand, tout en faisant le moins de mouvement possible. 1.2 analyse et résolution du problème Le problème se résoud simplement par récurence (soit n le nombre total de disques) : il faut 2n − 1 coups au minimum pour transférer les disques. pour n=1 : il sut de transférer le disque de la première tige à la tige d'arrivée. Il faut bien 21 − 1 = 1 coups pour faire cette opération. Supposons que l'on sache résoudre le problème pour (n−1) disques avec 2(n−1) −1 coups. Pour résoudre le problème avec n disques, il faut déjà libérer le disque le plus grand, donc transférer les (n − 1) disques sur la tige intermédiaire (2n−1 − 1 coups), transférer le disque le plus grand sur la tige de destination (2n−1 coups) et transférer les (n − 1) disques de la tige intermédiaire à la tige de destination (2n−1 − 1 + 2n−1 = 2n − 1 coups). L'algorithme qui résoud récursivement ce problème est basé sur le même principe que la démonstration ci dessus : Algorithm 1 Tour de Hanoi Entrées: (i, j, n) ∈ {1, 2, 3}2 × N si n 6= 0 alors T our de Hanoi(i, j 0 (6= i, 6= j), n − 1) deplacer(i, j) T our de Hanoi(j 0 , i, n − 1) nsi L'appel à Tour de Hanoi(i,j,n) transfert n disques de la tige i à la tige j ! ! Le programme des tour de Hanoi en Ocaml utilisé représente le contenu des tiges par 3 listes : (* renvoit une tige remplit avec n disques de taille 1 1 PROBLÈME DES TOURS DE HANOI 2 comprise entre 1 et n *) let rec init=function | 0->[]; | n->(init (n-1))@[n] ;; (* Transfert le disque du sommet de la tige origine à la tige destination*) let mouvement origine destination = (tige destination):=(List.hd (!(tige origine))): :(!(tige destination)); (tige origine):= List.tl (!(tige origine)) ;; 1.3 analyse de l'algorithme La complexité de cet algorithme est en O(2n ) comme vu précédement. Le premier appel récursif à la fonction n'est pas terminal. Cet algorithme n'est que partiellement dérécursiable. On peut donc avoir rapidement des problèmes de débordement de pile lorsque n augmente. On remarque, si on colorie les disques pairs en blancs et les disques impairs en noirs que deux disques de la même couleur ne sont jamais en contact. On peut prouver qu'il y a au plus un disque pair au sommet des tiges non vides en admettant la propriété précédante (il y a plus (ou autant) de disques impairs que de disques pairs et ils doivent être alternés). On peut connaitre le déplacement à opérer en fonction du coups précédant grace au deux règles précédantes : si le disque précédement déplacé était pair, la tige de destination reste inchangée, la tige d'origine change. si le disque précédement déplacé était impair, les tiges de destination et d'origine sont tous les deux changées et la sens du déplacement se fait dans le sens autorisé (un disque plus petit transféré sur un plus grand On a alors l'algorithme itératif suivant (au premier coup, il faut placer le disque 1 sur la tige 3 si n est impair, on peut le montrer très simplement par récurance sur l'algorithme récursif) 1 PROBLÈME DES TOURS DE HANOI Algorithm 2 Tour de Hanoi Entrées: n∈N si n est pair alors deplacer(1,2) depl-prec ← (1,2) sinon deplacer(1,3) depl-prec ← (1,3) nsi parité-prec ← impair tantque tige 3 non pleine faire si parité-prec = pair alors depl ← (j(6=depl-prec.orig),6=depl-prec.dest),depl-prec.dest) déplacement(depl) parité-prec ← parité(sommet(tige depl.dest)) depl-prec ← depl sinon depl ← (i(6=depl-prec.orig),j(6=depl-prec.dest,6=i)) depl ← bonsens(i,j) déplacement(depl) parité-prec ← parité(sommet(tige depl-prec.dest) depl-prec ← depl nsi n tantque 3