Ver Mensaje Individual
  #36 (permalink)  
Antiguo 27/11/2014, 12:51
Pantaláimon
 
Fecha de Ingreso: julio-2006
Ubicación: Barcelona
Mensajes: 244
Antigüedad: 18 años, 4 meses
Puntos: 32
Respuesta: Petando la pila. Problemas y retos usando recursividad.

Buenas!

Voy dejando mis soluciones:

La primera usa la siguiente regla recurrente:
Código :
Ver original
  1. comb(n, k) = n * comb(n-1, k) * (n - k) para n > k
Y se aprovecha de lo que observó leosansan. Es decir, que no hace falta hacer más de n/2 llamadas recurrentes. Aunque yo he usado una función auxiliar para así no comprobar una condición que será verdadera desde la segunda vez que se llama la función recursiva:

Código C:
Ver original
  1. unsigned icomb (unsigned n, unsigned k) {
  2.     if      (n < k) // fuera de la definición, comportamiento definido por mi arbitrariamente
  3.         return 0;
  4.     else if (n > k)
  5.         return n * icomb(n - 1, k) / (n - k);
  6.     else
  7.         return 1;
  8. }
  9.  
  10. unsigned comb (unsigned n, unsigned k) {
  11.     if (2 * k < n)
  12.         return icomb(n, n - k);
  13.     else
  14.         return icomb(n, k);
  15. }

Por lo que he visto las otras soluciones sobre comb se han basado en otra recurrencia parecida:
Código :
Ver original
  1. comb(n, k) = n * comb(n-1, k-1) / k
Pero mirando esto me he fijado en el caso de eferion y, a parte de algo extraño como multiplicar y luego dividir por el mismo número (n - k) / (n - k), no funciona tal como debería para n == k.
Hay que considerar que según la definición comb(n, n) == 1. En la solución de eferion devuelve 0.

Vamos al segundo problema. En dicho caso he aplicado el patrón mayoritario con una función collatz auxiliar. Sin embargo, en mi caso he añadido algo de "memoria" a la función auxiliar collatz con ayuda de una variable estática. De esta manera no hace cálculos repetidos:

Código C:
Ver original
  1. #include <stdio.h>
  2. #define N 100000
  3.  
  4. unsigned collatz (unsigned num)
  5. {
  6.     static int tabla[N] = {0};
  7.     if ( num <= 1 ) {
  8.         return 0;
  9.     } else if(num < N) {
  10.         if(tabla[num] != 0) {
  11.             return tabla[num];
  12.         } else {
  13.           return tabla[num] = 1 + collatz(num % 2 ? num * 3 + 1 : num / 2);
  14.         }
  15.     } else {
  16.         return 1 + collatz( num % 2 ? num * 3 + 1 : num / 2);
  17.     }
  18. }
  19.  
  20. double promedioCollatz (unsigned num)
  21. {
  22.   if (num > 0)
  23.     return (collatz(num) + (num - 1) * promedioCollatz(num - 1)) / num;
  24.   else
  25.     return 0;
  26. }
  27.  
  28. int main (void) {
  29.   unsigned i;
  30.   for (i = 1; i < 10000; ++i) {
  31.       printf("%6u %lf ", i, promedioCollatz(i));
  32.       puts("");
  33.   }
  34.   return 0;
  35. }

Cita:
Iniciado por Hackman
Para esta use un concepto un poco diferente, los programadores que tiene tiempo en esto seguramente van a observar un patrón bastante antiguo basado en los segmentos de la memoria, antiguamente no existía la memoria flat como ahora, así que había que trabajar con segmentos y offsets. Es solamente otro punto de vista el problema.
Me ha sorprendido tu versión. Buena aportación. Te animo a que sigas por aquí.

Un saludo! ... y mañana más
__________________
github.com/xgbuils | npm/xgbuils

Última edición por Pantaláimon; 27/11/2014 a las 12:56