Je résolvais récemment le problème des tours de Hanoi. J'ai utilisé une stratégie "Diviser pour régner" pour résoudre ce problème. J'ai divisé le problème principal en trois sous-problèmes plus petits et ainsi la récurrence suivante a été générée.
T (n) = 2T (n-1) +1
Résoudre cela conduit à
O (2 ^ n) [temps exponentiel]
Ensuite, j’ai essayé d’utiliser la technique de mémorisation pour la résoudre, mais là aussi, la complexité de l’espace était exponentielle et l’espace vide rapidement épuisé, et le problème demeurait insoluble pour les plus grands n.
Existe-t-il un moyen de résoudre le problème en moins de temps exponentiel? Quel est le meilleur moment où le problème peut être résolu?
Cela dépend de ce que vous voulez dire par "résolu". Le problème de la tour de Hanoi avec 3 chevilles et des disques n
nécessite des mouvements 2**n - 1
à résoudre. Ainsi, si vous souhaitez énumérer les mouvements, vous ne pouvez évidemment pas faire mieux que O(2**n)
, car énumérer k
choses est O(k)
.
D'autre part, si vous souhaitez simplement connaître le nombre de déplacements requis (sans les énumérer), le calcul de 2**n - 1
est une opération beaucoup plus rapide.
Il convient également de noter que l’énumération des déplacements peut être effectuée de manière itérative avec la complexité d'espace O(n)
comme suit (disk1
est le plus petit disque):
while true:
if n is even:
move disk1 one peg left (first peg wraps around to last peg)
else:
move disk1 one peg right (last peg wraps around to first peg)
if done:
break
else:
make the only legal move not involving disk1
Vous pouvez résoudre la récurrence et obtenir un formulaire fermé.
T (n) = 2 * T (n-1) + 1
T (n) = 2 * (2 * T(n-2) + 1) + 1
T (n) = (2 ^ 2) * T(n-2) + 2 ^ 1 + 2 ^ 0
T (n) = (2 ^ k) * T(n-k) + 2 ^ (k-1) + 2 ^ (k-2) + ... + 2 ^ 0
Résoudre cela le fermé de vient d'être
T (n) = (2 ^ n) - 1 avec T(0) = 0
Utilisez maintenant l’exponentiation en quadrillant.
Malheureusement, il est impossible de résoudre ce problème en moins de temps, car le nombre de mouvements nécessaires pour changer la position de toutes les tours de hanoi est exponentiel. La meilleure solution est donc linéaire en fonction du nombre d'étapes O (T), donc en nombre de la solution de queue est exponentielle O (2 ^ n)
Cela dépend un peu du type de représentation que vous acceptez. Imaginez la représentation suivante:
OneMove
from : integral
to : integral
Solution
step_one : optional reference to Solution
step_two : OneMove
step_three : optional reference to Solution
Une telle représentation peut en réalité être créée avec une complexité linéaire, car il y a beaucoup de répétition impliquée.
Je viens de l'essayer, la construction d'une telle solution pour la hauteur 64 a pris moins d'une milliseconde. Bien sûr, le parcourir prend toujours 2n-1 pas.
Vous n'avez pas spécifié de langue, mais si vous voulez du code en C++, supprimez une ligne.
Il y a exactement 2 ^ n-1 coups; par conséquent, pour les répertorier, nous ne pouvons pas faire mieux que la complexité temporelle de O (2 ^ n).
L'énumération des déplacements nécessaires est possible dans O(1) (ainsi, O (log n) si vous prenez des entiers de taille arbitraire)
(define (fbs n i) (if (even? n) (fbs (/ n 2) (+ i 1)) i))
(define (fb n) (fbs n 1))
(define (hanois n i m)
(
cond
((= i m) "DONE")
(else
(define k (fb i))
(print "move disk " k " " (if (even? (+ n k)) "left" "right"))
(hanois n (+ 1 i) m))))
(define (hanoi n) (hanois n 1 (expt 2 n)))
[Schème]
Notez que cet algorithme a une surcharge de log n due à l'arithmétique (et à l'algorithme fb
de trouver la position du bit de poids le moins significatif). Toute solution naïve impliquant tout type d’incrément/décrément sur un compteur aura le même temps système.