Premier Projet en OCaml

publicité
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
Téléchargement