Lección
La teoría — Explorador de árboles de recursión
Un árbol de recursión tiene un nodo por llamada: la raíz es la llamada que hiciste, y los hijos de un nodo son las llamadas que este realiza. De aquí se extraen tres números. El conteo de nodos representa el tiempo de ejecución en unidades de «una llamada». La altura indica la profundidad que alcanza la pila. Por último, el conteo de nodos diferentes equivale al tiempo de ejecución que obtendrías si cada respuesta se recordara la primera vez que se calcula.
Cómo leer lo que ves
La página se abre en fib(6), cuyo árbol es lo bastante pequeño para dibujarse entero: 25 nodos, 7 de los cuales representan la primera aparición de su subproblema. Por eso la tarjeta de problemas distintos indica 7 y la de llamadas por subproblema muestra 3,6. El anidamiento máximo es 5, a lo largo de fib(6) → fib(5) → … → fib(1). De las 25 llamadas, 13 alcanzan un caso base y las 12 restantes suman dos valores devueltos cada una.
- Falla cuando
- Las llamadas por subproblema son una promesa sobre la memoización, y Hanói es donde esa promesa se rompe. Hanói en n = 20 reporta 21 subproblemas distintos frente a 2.097.151 llamadas, es decir, 99.864,3 llamadas por subproblema, 95,8 veces la cifra de Fibonacci para el mismo valor de n. Memoizar esto no ahorra nada útil. La respuesta a
hanoi(20)es una lista de 1.048.575 movimientos, y devolver una lista recordada cuesta lo mismo que generarla. Una tabla de memoización resulta rentable cuando la respuesta es pequeña y el árbol es inmenso. La respuesta de Fibonacci es un solo entero; la de Hanói es el árbol transcrito por completo.
Problemas resueltos al detalle
-
La forma cerrada del recuento de llamadas cuando fib(10) ingenuo hace 177 llamadas 6 pasos
La herramienta dice que la versión ingenua de
fib(10)realiza 177 llamadas yfib(11)realiza 287. Encuentra la forma cerrada para el conteo de llamadas, demuéstrala y luego calcula hasta dónde llega la función ingenua de Fibonacci en un segundo dentro de una máquina capaz de procesar 108 llamadas por segundo.-
Suma uno a cada conteo: 178 y 288. Ambos son pares y sus mitades son 89 y 144, que corresponden a F11 y F12. Por tanto, la conjetura es C(n) = 2F(n+1) − 1, con F(1) = F(2) = 1.
-
El árbol explica de dónde surge esa duplicación. Cada nodo interno hace exactamente dos llamadas y cada hoja no hace ninguna. De este modo, un árbol con L hojas tiene L − 1 nodos internos y 2L − 1 nodos en total. La herramienta reporta 89 casos base para n = 10, y 2 × 89 − 1 = 177.
-
Primero los casos base.
fib(0)yfib(1)devuelven su valor sin recurrir, de modo que C(0) = C(1) = 1, y tanto 2F(1) − 1 como 2F(2) − 1 equivalen a 1. -
Ahora el paso de inducción. Supón que la fórmula se cumple para n − 1 y n − 2. La llamada en n equivale a un nodo más sus dos subárboles. Debajo, los dos números de Fibonacci se colapsan por la propia definición de la secuencia. Establecer n = 11 da como resultado 2 × 144 − 1 = 287, que es justo lo que imprime la herramienta.
-
Deja el árbol a un lado. La fórmula de Binet establece que F(m) = (φm − ψm)/√5 con φ = 1,6180 y |ψ| < 1, por lo que F(m) es φm/√5 redondeado al entero más cercano, y C(n) ≈ 2φn+1/√5. Un segundo a 108 llamadas por segundo permite realizar 108 llamadas, lo cual fija φn+1 en 1,1180 × 108.
-
Toma logaritmos. ln(1,1180 × 108) = 18,5323 y ln φ = 0,4812, así que n + 1 = 38,51 y n = 37,5. Redondea hacia abajo, ya que una llamada fraccionaria no termina.
Respuesta
n = 37. La herramienta confirma a los dos vecinos: 78.176.337 llamadas en n = 37 y 126.491.971 en n = 38. A partir de ahí, cada aumento de 1,44 en n duplica el trabajo, porque ln 2 / ln φ = 1,44. Mientras tanto, la tarjeta de subproblemas distintos en n = 37 indica 38. Setenta y ocho millones de llamadas para responder treinta y ocho preguntas es el argumento a favor de la programación dinámica en una sola frase.
-
-
Tres ramas que crecen más despacio que dos 6 pasos
Las escaleras de tres pasos se llaman a sí mismas tres veces en cada nodo; las Torres de Hanói se llaman dos. Carga Escaleras 20, tres ramas, averigua cuál de los dos árboles crece más deprisa y decide cuánto vale el factor de ramificación como guía.
Abre este problema en la herramienta
-
Lee la recurrencia de la definición y no del dibujo. Una llamada para el propio nodo, luego tres más en n − 1, n − 2 y n − 3, y todo lo que esté en 2 o por debajo devuelve su valor sin recurrir.
-
Supón que el conteo crece geométricamente, C(n) ≈ A xⁿ, y sustituye. Divide todo entre x elevado a n − 3 y el 1 inicial se queda atrás como ruido de orden inferior, lo que deja una cúbica. Su única raíz real es 1,8392868, la constante tribonacci.
-
La misma receta en las otras dos definiciones. Fibonacci se llama en n − 1 y n − 2, así que x² = x + 1 y la raíz es φ = 1,6180340. Hanói se llama dos veces en n − 1, así que x = 2 y no hay nada que resolver.
-
Compruébalo en lugar de creértelo. Pon n en 29, lee la tarjeta de llamadas realizadas, pon n en 30, léela otra vez y divide. Las escaleras dan 1,83929, Fibonacci 1,61803 y Hanói exactamente 2. Cinco decimales en las tres.
-
Lo que la raíz no te da es el conteo. 1,8393²⁰ es 196.331 mientras que la tarjeta marca 128.287, así que hay un factor de 0,65 delante; las llamadas de Hanói son exactamente 2ⁿ⁺¹ − 1, un factor de 2. Los casos base fijan esa constante y la recurrencia fija la raíz, y solo la raíz decide quién gana a la larga.
-
El largo plazo llega pronto aquí. En n = 20 Hanói hace 16,3 veces más llamadas que las escaleras, y en n = 30 hace 37,8 veces más. La proporción se duplica cada 8,3 pasos, ya que ln 2 dividido entre ln(2 ÷ 1,8393) es 8,27.
Respuesta
Hanói crece más deprisa, 2 contra 1,8393, y la tercera rama no le cuesta a las escaleras nada que no puedan pagar. El factor de ramificación es una cota superior de la tasa de crecimiento, y solo se alcanza cuando cada hijo es un paso más pequeño. Las escaleras gastan dos de sus tres llamadas en argumentos que bajan 2 y 3, y esos subárboles son lo bastante baratos como para no llegar nunca a sumar la rama que parecían haber ganado.
Lo que hay que quedarse es la receta, porque funciona con una definición que nadie te ha resuelto antes. Cuenta los hijos, anota cuánto baja el argumento cada uno, escribe x elevado a la bajada mayor como suma de x elevado a las bajadas restantes y toma la mayor raíz real. Va con una advertencia: esto es un hecho sobre el árbol ingenuo, y el árbol ingenuo no es lo que nadie escribiría. La tarjeta de subproblemas distintos marca 21 en n = 20 para las escaleras y 21 para Hanói, así que una memoización elimina el exponente por completo y la tasa de crecimiento deja de importar. -
Ruta de aprendizaje