Está en la página 1de 11

Recursión, otra visita

Jesús Ravelo
Cristina Zoltan
Dpto. de Computación y Tecnologı́a de la Información
Universidad Simón Bolı́var
Caracas, Venezuela
(Borrador)
23 de enero de 2001

1 El problema de las torres de Hanoi: marco


histórico
El problema que presentamos deriva de un mito alrededor de la vida del
Universo. El mito dice que Dios habı́a colocado en un monasterio en Hanoi
tres pines (de materiales preciosos), y sobre uno de ellos habı́a colocado 64
discos (de oro puro) en orden decreciente de diámetro. La tarea de los monjes
consistı́a en trasladar la torre del pin original a otro. La restricción impuesta
por el material de los discos es que solamente se podı́a mover un disco a la
vez, y el pin de llegada debı́a tener en el tope un disco de diámetro mayor
al disco que se estaba moviendo. Con estas sencillas reglas estableciendo la
tarea de los monjes, el mensaje final era que cuando los industriosos monjes
terminaran su tarea el mundo desaparecerı́a. El mundo académico del siglo
XIX se interesó en el problema de calcular el tiempo que le quedaba al mundo,
suponiendo que los monjes trabajaran incesantemente.

1
Hanoi 2

2 Marco Conceptual
El proceso consiste en trasladar la pila de discos, todos de diametro diferente,
del pin ORIGEN al pin DESTINO. Esto nos llevarı́a de la situación que
vemos en la figura 1 a la de la figura 2. Si tuviesemos una grúa capaz de
levantar todos los pines lo harı́amos en un solo movimiento. Pero las reglas
del juego permiten mover un solo disco a la vez.
4.0in2.2inc:/cris/hanoi/inicial.bmp

Figura 1: Estado inicial

4.0in2.2inc:/cris/hanoi/final.bmp

Figura 2: Estado final

Las reglas del juego nos permiten mover un solo disco a otro pin, con
la restricción que un disco puede colocarse en un pin que está vacı́o o tiene
disco superior de diámetro mayor al que estamos colocando.

Definición – Configuración válida de Hanoi:


(i) Denotaremos como k.i al diámetro del disco i en el pin k. Los discos en
un pin los numeraremos tomando como 0 al que está arriba en el pin.
(Esto significa que manejaremos los pines como secuencias de números
naturales, denotando k.i al elemento i de la secuencia k.)
(ii) (∀k, i : k ∈ {ORIGEN , DESTINO, AUXILIAR} ∧ 0 ≤ i < |k| − 1 :
k.i < k.(i + 1)), siendo |k| la cantidad de discos que están en el pin k.
Por lo anterior, las reglas de juego pueden resumirse en:

Definición – Reglas de juego de las torres de Hanoi:


(i) Si se va a mover un disco del pin i al pin j el movimiento será válido si

|j| > 0 ⇒ i.0 < j.0 .


Hanoi 3

(ii) Después de realizar el cambio, el pin i ha perdido un disco por lo cual


si tenı́a p discos quedará con p − 1 discos, y el pin j ha ganado un disco
por lo que si tenı́a r discos inicialmente la operación de movimiento le
agregará un disco.

En la configuración inicial dada en la figura 1 el pin ORIGEN tiene 5


discos, mientras que los pines DESTINO y AUXILIAR no tienen pines. El
tamaño del problema del caso de la figura 1 es 5.
Una estrategia de solución del problema planteado es tener fe y pensar
que, si bien no tenemos una grúa que traslade N discos de un pin a otro,
podemos pensar en tener: primero, una operación de traslado de una pila
de discos de un pin a otro, permitiendo usar el tercer pin como auxiliar;
segundo, una operación de movimiento de un disco de un pin a otro. Daremos
a continuacón la semántica de estos dos operadores.

Definición – Operador de traslado de un conjunto de discos, HA-


NOI:

(i) Llamaremos al operador HANOI.

(ii) Los argumentos del operador serán:

– Número de discos que deseamos trasladar.


– Pin de origen.
– Pin de destino.
– Pin auxiliar.

(iii) El formato será:


proc HANOI (entrada N : natural;
entrada-salida ORIGEN ,DESTINO,AUXILIAR : pines)

(iv) Este operador podrá aplicarse siempre que:

– N >0.
– El pin ORIGEN tenga al menos N discos: |ORIGEN | ≥ N .
– El pin DESTINO pueda recibir los discos que se envı́an:

|DESTINO| > 0 ⇒ ORIGEN .(N − 1) < DESTINO.0 ,


Hanoi 4

y lo mismo para el pin AUXILIAR:

|AUXILIAR| > 0 ⇒ ORIGEN .(N − 1) < AUXILIAR.0 .

(v) Podemos demostrar que si el operador recibe una configuración válida,


entonces devuelve una configuración válida.

Definición – Operador de traslado de un solo disco, MOVER:


(i) Llamaremos al operador MOVER.

(ii) Los argumentos del operador serán:

– Pin de origen.
– Pin de destino.

(iii) El formato será


proc MOVER (entrada-salida ORIGEN ,DESTINO : pines)

(iv) El disco que va a trasladarse es el ORIGEN .0 , y por tanto se re-


quiere que |ORIGEN | > 0 . Este disco será colocado como el disco
DESTINO.0 .

(v) Este operador es válido si preserva las reglas del juego. Por lo tanto,
también se requiere que:

|DESTINO| > 0 ⇒ ORIGEN .0 < DESTINO.0 .

3 Recursión
Una técnica muy usual en computación para la solución de problemas es la
técnica de recursión. Este método consiste en tratar de resolver un proble-
ma de tamaño N en base a acciones que incluyan la resolución del mismo
problema, pero de tamaño menor. Este mecanismo es efectivo siempre que
se conozca una solución para el problema dado de tamaño pequeño.
En el caso de las torres de Hanoi, el tamaño del problema puede pensarse
que es el número de discos a trasladar, y es claro que HANOI (1, A, B, C)
es igual a MOVER (A, B) . Esta certeza de saber cómo resolver el problema
para tamaños reducidos se conoce como la terminación de la recursión.
Hanoi 5

Veremos que podemos plantear la solución del problema de los monjes


pensando en que, para el caso N > 1, podemos mover N − 1 discos del
pin ORIGEN al pin AUXILIAR, luego mover el disco restante en el pin
ORIGEN al pin DESTINO, y finalmente mover nuevamente los N − 1 pines
del pin AUXILIAR al pin DESTINO. Por lo tanto, podemos expresar la
solución como:
HANOI(N,ORIGEN,DESTINO,AUXILIAR)
begin
si N=1 entonces MOVER(ORIGEN,DESTINO)
sino
begin
HANOI(N-1,ORIGEN,AUXILIAR,DESTINO);
MOVER(ORIGEN,DESTINO);
HANOI(N-1,AUXILIAR,DESTINO,ORIGEN)
end
end
Gráficamente, para el ejemplo que mostramos anteriormente, la primera
lı́nea del caso en que N no es 1 darı́a como resultado la configuración de la
figura 3.

4.0in2.2inc:/cris/hanoi/linea1.bmp

Figura 3: Resultado después de


HANOI (5 − 1, ORIGEN , AUXILIAR, DESTINO)

La segunda lı́nea del caso en que N no es 1 produce como resultado la


configuración que se muestra en la figura 4.

4.0in2.2inc:/cris/hanoi/linea2.bmp

Figura 4: Resultado después de MOVER (ORIGEN , DESTINO)

La tercera lı́nea del caso en que N no es 1 darı́a como resultado la confi-


guración que se muestra en la figura 5.
Como vemos en la secuencia de figuras 3 a 5, cada una de ellas es una
configuración válida de las torres de Hanoi. Sin embargo, para asegurar
Hanoi 6

4.0in2.2inc:/cris/hanoi/linea3.bmp

Figura 5: Resultado después de


HANOI (5 − 1, AUXILIAR, DESTINO, ORIGEN )

configuraciones válidas debemos asegurarnos que todas las configuraciones


intermedias son también válidas.

4 Validez de la solución obtenida


La solución del problema de las torres de Hanoi ha sido presentada como
una solución recursiva, ya que expresamos la solución del problema HANOI
de tamaño N en términos de llamadas a la solución de un problema similar
pero de tamaño N − 1. Definamos la semántica de los operadores mediante
pre- y post-condiciones, para luego demostrar que la solución propuesta es
correcta:

proc HANOI (entrada k : natural; entrada-salida A,B,C : pines)


 
 Pre:
 A = A0 k A1 ∧ |A0 | = k > 0 
B = B0
C = C0

 

 

 Post: A = A1 

B = A 0 k B0
C = C0

 

proc MOVER (entrada-salida A,B : pines)


( )
Pre: A = hxi k A0
B = B0
( )
Post: A = A0
B = hxi k B0

En la figura 6 se presenta el programa desarrollado para la solución del


problema de HANOI, con las anotaciones que muestran su correctitud con
respecto a la semántica pre/post-condición dada. Vemos que la condición
inicial y la condición final del programa anotado corresponden, respectiva-
mente, a la pre- y la post-condición de la definición semántica.
Hanoi 7

HANOI(k,A,B,C)
begin
{ A = A0 k A1 ∧ |A0 | = k > 0 ∧ B = B0 ∧ C = C0 }
( )
(como k > 0 , tenemos que A0 puede ser expresado como A00 k hxi )
A = A00 k hxi k A1 ∧ |A00 | = k − 1 ≥ 0 ∧ B = B0 ∧ C = C0
si k=1 entonces
( )
(como k = 1 , tenemos que A00 = hi )
A = hxi k A1 ∧ B = B0 ∧ C = C0
MOVER(A,B)
{ A = A1 ∧ B = hxi k B0 ∧ C = C0 }
{ A = A1 ∧ B = A00 k hxi k B0 ∧ C = C0 (pues A00 = hi ) }
sino
begin
( )
(en este caso se cumple k > 1 )
A = A00 k hxi k A1 ∧ |A00 | = k − 1 > 0 ∧ B = B0 ∧ C = C0
HANOI(k-1,A,C,B);
{ A = hxi k A1 ∧ B = B0 ∧ C = A00 k C0 ∧ |A00 | = k −1 > 0 }
MOVER(A,B);
{ A = A1 ∧ B = hxi k B0 ∧ C = A00 k C0 ∧ |A00 | = k −1 > 0 }
HANOI(k-1,C,B,A)
{ A = A1 ∧ B = A00 k hxi k B0 ∧ C = C0 }
end
{ A = A1 ∧ B = A00 k hxi k B0 ∧ C = C0 }
{ A = A1 ∧ B = A0 k B0 ∧ C = C0 (pues A00 k hxi = A0 ) }
end

Figura 6: Solución recursiva del problema HANOI con anotaciones


Hanoi 8

Note que las anotaciones indican que efectivamente se han trasladado los
k discos del tope del pin A al pin B dejando inalterado el pin C.
Es importante volver a destacar la necesidad de disminuir el tamaño del
problema en las llamadas recursivas, es decir, en las llamadas al mismo proce-
dimiento con el que se está resolviendo el problema. En nuestro caso, vemos
que la solución propuesta para HANOI de tamaño k sólo hace llamadas a
HANOI para problemas de tamaño k − 1. La correctitud de esta solución
recursiva depende fuertemente de este hecho, lo cual está estrechamente re-
lacionado con la noción de función de cota para demostrar correctitud de
soluciones iterativas. Para iteraciones, las demostraciones de correctitud re-
quieren el uso de una función de cota que garantice terminación; usualmente
ésta es una función entera que decrece estrictamente en cada iteración y que
está acotada inferiormente. En nuestra solución de HANOI, el tamaño k
del problema cumple el rol de la función de cota: cada llamada recursiva se
realiza para un valor estrictamente menor; y la cota inferior es 1, valor para
el cual resolvemos el problema sin utilizar recursión.
Por último, veamos que, de acuerdo a la semántica especificada para HA-
NOI, hemos resuelto nuestro problema inicial. Si tenemos un pin ORIGEN
no-vacı́o con N discos, y pines DESTINO y AUXILIAR vacı́os, se estarı́a
cumpliendo la condición
 

 ORIGEN = ORIGEN 0 ∧ |ORIGEN | = N > 0 

DESTINO = hi
AUXILIAR = hi

 

(donde ORIGEN 0 nos permitirá referirnos luego al valor inicial de ORIGEN )


y queremos mostrar que una llamada de la forma

HANOI (N, ORIGEN , DESTINO, AUXILIAR)

serı́a suficiente.
Con tal pre-condición, estarı́amos instanciando nuestra solución mediante
la substitución

k, A, B, C := N, ORIGEN , DESTINO, AUXILIAR ,

e instanciarı́amos las variables de especificación de acuerdo a la substitución

A0 , A1 , B0 , C0 := ORIGEN 0 , hi, hi, hi .


Hanoi 9

Realizando las substituciones indicadas en la semántica definida para HA-


NOI, que se mostró satisfecha por la solución propuesta, tendrı́amos que la
llamada en cuestión cumplirı́a:
 

 ORIGEN = ORIGEN 0 ∧ |ORIGEN | = N > 0 

DESTINO = hi
AUXILIAR = hi

 

HANOI (N, ORIGEN , DESTINO, AUXILIAR)


 

 ORIGEN = hi 

DESTINO = ORIGEN 0
AUXILIAR = hi

 

Vemos en la post-condición que efectivamente se han trasladado los N discos


del pin ORIGEN al pin DESTINO dejando inalterado el pin AUXILIAR.

5 Complejidad de la solución
Por razones de completitud del análisis y solución de un problema, presen-
tamos brevemente el análisis de la complejidad de la solución obtenida.
Llamemos H(N ) al número de operaciones requeridas para solucionar un
problema HANOI de tamaño N , y asumamos que el número de operaciones
que realiza MOVER es una constante C. Vemos entonces que podemos
expresar H(N ), según la solución presentada, como
(
C si N = 1 ,
H(N ) =
2 ∗ H(N − 1) + C si N > 1 .

En base a esta fórmula, una primera exploración de la función H, asu-


miendo que N es un número suficientemente grande, nos indicarı́a lo siguien-
te:

H(N ) = 2 ∗ H(N − 1) + C
= 2 ∗ (2 ∗ H(N − 2) + C) + C
= 22 ∗ H(N − 2) + 2 ∗ C + C
= 22 ∗ (2 ∗ H(N − 3) + C) + 2 ∗ C + C
= 23 ∗ H(N − 3) + 22 ∗ C + 2 ∗ C + C
= 23 ∗ (2 ∗ H(N − 4) + C) + 22 ∗ C + 2 ∗ C + C
Hanoi 10

= 24 ∗ H(N − 4) + 23 ∗ C + 22 ∗ C + 2 ∗ C + C
= ...
Esta exploración sugiere que, en el caso general, se cumple que:
H(N ) = 2i ∗ H(N − i) + ( j : 0 ≤ j < i : 2j ∗ C) si N > i .
P

Esto puede ser demostrado por inducción sobre i, para i ≥ 1 .


Resolviendo para el caso N − i = 1 , resulta lo siguiente:
H(N )
= { fórmula anterior con i = N − 1 }
N −1
2 ∗ H(1) + ( j : 0 ≤ j < N − 1 : 2j ∗ C)
P

= { pues H(1) = C }
N −1
2 ∗ C + ( j : 0 ≤ j < N − 1 : 2j ∗ C)
P

= { agregando un término a la sumatoria }


( j : 0 ≤ j < N : 2j ∗ C)
P

= { sacando factor común }


( j : 0 ≤ j < N : 2j ) ∗ C
P

= { resolviendo la sumatoria }
(2N − 1) ∗ C .
Hemos demostrado entonces que, en el caso general, se cumple
H(N ) = (2N − 1) ∗ C .
El caso particular del tiempo requerido por los monjes de Hanoi para
mover los 64 discos de oro de los pines resulta ser un valor de 20 cifras signi-
ficativas multiplicado por el tiempo requerido para mover un disco. Si somos
optimistas y consideramos que los monjes mueven un disco por segundo, sin
detenerse ni de dı́a ni de noche, podemos estar tranquilos ya que la desapa-
rición del mundo, pronosticado en el mito, tardarı́a aún unos seis millardos
de centurias.

6 Bibliografı́a
1. ABERNETHY, Kenneth & ALLEN, J. Thomas, “Exploring the Science
of Computing, A Laboratory Approach with PASCAL”. PWS Publis-
hing Company, Boston, Massachusetts, 1994.
Hanoi 11

2. MEZA, Oscar J., “Introducción a la programación”. Departamento


de Computación y Tecnologı́a de la Información, Universidad Simón
Bolı́var, 2000.

También podría gustarte