Ver Mensaje Individual
  #100 (permalink)  
Antiguo 10/12/2014, 17:23
Avatar de leosansan
leosansan
 
Fecha de Ingreso: mayo-2012
Ubicación: GRAN CANARIA
Mensajes: 194
Antigüedad: 12 años
Puntos: 49
Respuesta: Petando la pila. Problemas y retos usando recursividad.

Antes que nada dar la enhorabuena a los participantes , especialmente en el caso de los números vampiros. Ha sido un placer ver los distintos enfoques que se han aplicado para resolver el mismo problema, todo un placer aprender de ustedes.

En realidad considero ganadores morales a todos ya que los tiempos para un solo número son parecidos, no así para un intervalo de 2000000 de valores donde se penaliza ciertas licencias. Pongo como ejemplo mi caso en que inicializo una matriz y al aplicarlo a esos dos millones pues claro que se ralentiza mucho.

Así que no me he resistido a dar, aunque fuera de tiempo cosa que no me importa mucho, "lo importante es participar aunque sea tarde", una solución más matemática al estilo de la propuesta de kutcher.

Me diferencia de la de kutcher pequeños detalles solamente ya que en lo básico es similar:

* No hago uso de macros.

* No uso variables ni arrays globales.

* Calculo los máximos y mínimos de forma ligeramente diferente ya que no hago uso de arrays para el calculo de los mismos.

* Y lo más importante, aplico otra expresión matemática para verificar que los dígitos del número y los factores tienen el mismo conjunto de valores.

Y para esto último he hecho uso del Teorema [47] de Cálculo de León, que dice algo así que para números de un número par de cifras ( al menos hasta ocho ) que se pueden descomponer en dos factores con la mitad de cifras cada uno y el mismo conjunto de cifras, se verifica que la suma de los dígitos del número más las de sus potencias sexta es igual a la suma de esas mismas cantidades aplicadas a sus factores.

Con todo ello me queda el código:

Código C++:
Ver original
  1. #include<stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4.  
  5. int SumaDigitos( int num , int suma ) {
  6.   int factor = ( ( num ) % 10 ) * ( ( num ) % 10 ) ;
  7.   if ( num ) { suma += ( num ) % 10 + factor * factor * factor ; return SumaDigitos ( num / 10 , suma ) ; }
  8.   else return suma ;
  9. }
  10.  
  11. int criba ( int numero , int num_1 , int nMax , int sumaDigitNum  ) {
  12.   static int conT = 0 ;
  13.   int num_2 = numero / num_1 ;
  14.   if( num_1 <= nMax ) {
  15.     num_2 = numero / num_1;
  16.     if ( num_1 * num_2 == numero && ( num_1 % 10 != 0 || num_2 % 10 != 0  )
  17.         && sumaDigitNum == SumaDigitos( num_1 , 0 ) + SumaDigitos( num_2 , 0 ) )
  18.       { printf ( "%d = %d x %d  [%3u]\n", numero , num_1 , num_2, ++conT )  ; return 1 ; }
  19.   return criba ( numero , num_1 + 1 , nMax , sumaDigitNum ) ;
  20.   }
  21.   return 0 ;
  22. }
  23.  
  24. int esVampiro( int numero ) {
  25.   int  sumaDigitNum = SumaDigitos ( numero , 0 ) , ndigits = log10 ( numero ), nMin = 1 + numero / pow ( 10 , 1 + ndigits / 2 ), nMax = sqrt ( numero ) ;
  26.   if ( --ndigits %2 != 0 ) return 0 ;
  27.   return ( criba ( numero , nMin , nMax , sumaDigitNum ) == 0 ) ? 0 : 1 ;
  28. }
  29.  
  30. int main ( void ) {
  31.   int i ;
  32.   for (i = 10000000, esVampiro ( i ) ; i <= 12000000 ; i ++ , esVampiro ( i ) ) ;
  33.   return  0 ;
  34. }
  35.  
  36. /**
  37. int main ( void ) {
  38.   return  printf ( "\n!!! Como lo quiere Pantalaimon ( 0 - 1 ) !!! ==> : [%d]\n\n" , esVampiro ( 11420923 ) ) , 0 ;
  39. }
  40. **/

Y ahora si que estoy en los tiempos del ganador: ¡¡¡¡ kutcher ¡¡¡.

Y ahora un par de comentarios respecto de los códigos de los ganadores:

kutcher:

* Se produce más una salida repetida en los valores, pero sin mayor importancia ya que son apenas dos o tres valores, dependiendo del tamaño y amplitud de la muestra.

Como ejemplo, y usando un contador, se obtiene como salida:

Código C++:
Ver original
  1. 125433 = 231 x 543  [ 23]
  2. 125460 = 204 x 615  [ 24] <==
  3. 125460 = 246 x 510  [ 25] <==
  4. 125500 = 251 x 500  [ 26]
  5. .....................
  6. .....................

Observa que el valor 24 y 25 se repite, cuando no estamos en el caso de buscar distintos colmillos de un mismo número. Creo que el pequeño bug se corrige cambiando:

Código C++:
Ver original
  1. comprobar(min + 1, max, num, b, t, es);
  2.     }else return es > 0 ? 1 : 0;

por:

Código C++:
Ver original
  1. if ( es > 0 ) return 1 ;
  2.         comprobar(min + 1, max, num, b, t, es);
  3.     }else return 0;

Una nimiedad, vamos.

Y ahora una duda que tengo, a ver si me ayudan a resolverla. Al hacer kutcher uso de desplazamientos de bits se obtienen valores muy grandes., si es que yo he interpretado de forma correcta la operación desplazamiento¡to , y si no es así aclarármelo por favor. En esencia esto es lo que yo "creo" que hace:

Código C++:
Ver original
  1. 1 << ( 35 % 10 ) * 6 = 1 << 5 * 6 = 2^30 = 1073741824
  2.  
  3. 5 + 5^6 = 15630

Se ve la diferencia en cuanto al tamaño del método de kutcher y el mío, todo suponiendo que mi interpretación es correcta.

Y la duda viene cuando la cifra módulo es, por ejemplo, nueve, ya que este caso se obtendría:

Código C++:
Ver original
  1. 1 << ( 39 % 10 ) * 6 = 1 << 9 * 6 = 2^54 = 18014398509481984
  2.  
  3.  9 + 9^6 = 531 450

¡¡¡ Duda, duda ¡¡¡. ¿Y cúal es la duda?. Sencillo el valor que se obtiene supera los límites del tipo "int" y como los resultados obtenidos con el código son correctos me lleva a plantearme dos posibilidades:

** El programa trunca el valor, pero al hacerlo tanto en la cifra del número como en la del factor donde aparece dicho dígito, se compensan los errores.

** El programa al encontrarse un valor tan alto pasa a tomarlo como float, manteniendo todas sus cifras, y tampoco se produce error.

En mi caso, al no obtener ni de lejos valores tan altos, no se me plantea esa duda.

Pantaláimon: Me mosquea el resultado que obtengo. Le he añadido al código que colgaste en Internet este main:

Código C++:
Ver original
  1. int main ( void ) {
  2.   int i ;
  3.   for (i = 1260   ; i <= 1260   ; i ++  )
  4.     if ( esVampiro ( i ) == 1 ) ;
  5.   return  0 ;
  6. }

Y el resultado obtenido es realmente extraño:

Código C++:
Ver original
  1. 13 x 99 = 1260

No es ya que las cifras de los factores no coincidan con la del número, es que ni el producto da dicho número. Igual estoy torpe y y no manejo con soltura el copy-paste, pero es que al aplicarlo a un intervalo da como vampiros los que no son y como no a los que si lo son. A ver si me puedes ayudar a entender lo que ocurre

Espero que quede de manifiesto que no sólo nos limitamos a colgar códigos en el tema sino en que como ven esos códigos se estudian, vamos que no es un trabajo que acabe es saco roto.

Y respecto a los otros códigos sólo comentar que de todos he aprendido algo que al fin y al cabo es una de ventajas que obtenemos en este tema. Gracias.

Y ya tan sólo............ ¡¡¡¡ FELICES FIESTAS ¡¡¡¡

¡¡¡Saluditos!!!