Ver Mensaje Individual
  #123 (permalink)  
Antiguo 17/12/2014, 10:23
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.

Bueno, mi solución al segundo problema es esta.

C++11
Código C++:
Ver original
  1. #include <iostream>
  2. #include <map>
  3. #include <cmath>
  4.  
  5. std::map< int, std::pair<int, int> > descomposiciones;
  6.  
  7. void descomponNumero(int num, int root, int i = 2 ) {
  8.     auto iterator = descomposiciones.find(num);
  9.     if (iterator == descomposiciones.end()) {
  10.         if (num > 1 && i <= root) {
  11.             if (num % i == 0) {
  12.                 int n = num / i;
  13.                 descomposiciones[num] = std::make_pair(i, n);
  14.                 descomponNumero(n, (int) std::sqrt(n));
  15.             } else {
  16.                 descomponNumero(num, root, i + 1);
  17.             }
  18.         } else {
  19.             descomposiciones[num] = std::make_pair(num, 1);
  20.         }
  21.     }
  22. }
  23.  
  24. void mostrar(int num, int factor, int exponente, int ver) {
  25.     auto pair = descomposiciones[num];
  26.     if (num <= 1 || factor != pair.first) {
  27.         if (ver)
  28.             std::cout << factor;
  29.         if (exponente > 1 && ver) {
  30.             std::cout << "^" << exponente;
  31.         }
  32.         if (pair.first > 1 && ver) {
  33.             std::cout << " * ";
  34.         }
  35.         exponente = 0;
  36.     }
  37.     if (num > 1) {
  38.         mostrar(pair.second, pair.first, exponente + 1, ver);
  39.     }
  40. }
  41.  
  42. void descompon(int a, int b, int ver) {
  43.     if (a <= b) {
  44.         descomponNumero(a, (int) std::sqrt(a));
  45.        
  46.         if (ver)
  47.             std::cout << a << " = ";
  48.         mostrar(a, descomposiciones[a].first, 0, ver);
  49.         if (ver)
  50.             std::cout << std::endl;
  51.  
  52.         descompon(a + 1, b, ver);
  53.     }
  54. }
  55.  
  56. int main() {
  57.     descompon(2, 100000, 0);
  58.     /*for (auto  i : descomposiciones) {
  59.         std::cout << i.first << " -> " << i.second.first << ", " << i.second.second << std::endl;
  60.     }*/
  61.     return 0;
  62. }

La idea a la hora de resolverlo es no hacer cálculos repetidos. Si he descompuesto los números del 2 al 15, cuando tenga que descomponer el 16 no hace falta que repita cálculos. Pues los factores de 16 son igual a 2 + los factores de 8 (previamente calculados).

Buenas, eferion.
Cita:
Iniciado por eferion
En ambos casos el algoritmo calcula de forma correcta la descomposición del número, que es lo que se pide en el enunciado...
El problema es que calcular de forma correcta la descomposición es una tarea ambigua. Yo podría decir que he descompuesto los números del 2 al 10 cuando genero un map que guarda la siguiente información:

2 -> 2, 1
3 -> 3, 1
4 -> 2, 2
5 -> 5, 1
6 -> 2, 3
7 -> 7, 1
8 -> 2, 4
9 -> 3, 3
10 -> 2, 5

Alguien me diria:
- ¡Ei, que el 8 no lo has descompuesto del todo! Has parado la descomposición en el 4.
Pero yo podría decir:
- No es cierto, la tarea de descomponer el 8 la he realizado. Pues he descompuesto el 8 en 2 * 4 y previamente el 4 lo he descompuesto en 2 * 2.

Con lo cual el cálculo de descomposición de los números del 2 al 10 lo he hecho. Ahora la única tarea que me quedaría seria mostrarlo por pantalla. Pero claro, al igual que tu no haces los cálculos para ponerlo bonito en pantalla, yo podría decir lo mismo y implementar descompon así:
Código C++:
Ver original
  1. void descompon(int a, int b, int ver) {
  2.     if (a <= b) {
  3.         descomponNumero(a, (int) std::sqrt(a));
  4.        
  5.         if (ver) {
  6.             std::cout << a << " = ";
  7.             mostrar(a, descomposiciones[a].first, 0);
  8.             std::cout << std::endl;
  9.         }
  10.  
  11.         descompon(a + 1, b, ver);
  12.     }
  13. }
Ya que la tarea dentro del if (ver) {...} sólo coge los datos de descomposiciones y con éstos lo imprime tal como indica el enunciado. Es decir, una tarea de ponerlo bonito, pero no el cálculo real de la descomposición.

¿Ves correcto que pueda hacer esto?

Yo creo que no, el enunciado, a parte de calcular la factorización de un rango de números también pide mostrarlo bonito. Por tanto, los cálculos para ponerlo bonito también deben evaluarse. Con lo cual mi propuesta sería esta, realmente:

Código C:
Ver original
  1. void bucleChequeo( int numero, int candidato, int primerPrimo, int ver )
  2. {
  3.   int exp = ComprobarPrimo( &numero, candidato );
  4.   if ( exp > 0 )
  5.   {
  6.     if ( primerPrimo == 0 && ver ) printf( " *" );
  7.     if ( exponente == 1 && ver )
  8.       printf( " %d", base );
  9.     else if ( exponente > 0 && ver )
  10.       printf( " %d^%d", base, exponente );
  11.  
  12.     primerPrimo = 0;
  13.   }
  14.  
  15.   candidato += 2;
  16.   if ( numero > 1 )
  17.     bucleChequeo( numero, candidato, primerPrimo, ver );
  18. }

Edit: Antes he dicho que la tarea de factorizar un rango de números es ambigua, y no he explicado la razón. El problema es que cualquier tarea es ambigua si no se dice sobre que estructura de datos se guarda esa información. En anteriores problemas el valor debía devolverse en un array, en un string, en un entero. Aquí la "estructura de datos" en la que se debe guardar la informació es la salida estándar. Por eso creo que está bien evaluar esos cálculos dentro del tiempo de ejecución. Si no, cosas como mi anterior ejemplo podrían ser válidas.

Ese es mi razonamiento. Espero haberlo explicado bien ahora.

Un saludo!
__________________
github.com/xgbuils | npm/xgbuils

Última edición por Pantaláimon; 17/12/2014 a las 10:42