Ver Mensaje Individual
  #5 (permalink)  
Antiguo 03/05/2016, 03:56
eferion
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: recursividad c++ hallar todas las posibles soluciones de la suma de un ve

Yo este problema lo solucionaría un poco con ayuda de contenedores, ya que una secuencia de elementos puede tener un número indeterminado de posibles soluciones, cada una de ellas con un número indeterminado de elementos (eso sí, num de elementos de la solucion <= num de elementos del vector).

La desventaja de usar, como es tu caso, un vector de bool es que el reinicio de los valores has de realizarlo con sumo cuidado si no quieres acabar mal parado.

El caso es que si cada llamada recursiva recibe un vector de elementos (la combinación que se está comprobando actualmente) es sencillo realizar todas las combinatorias.

Entonces, la función recursiva podría tener esta firma:

Código C++:
Ver original
  1. typedef std::vector<int> Items;
  2. typedef std::vector<Items> Resultado;
  3.  
  4. Resultado suma( int* ptr, int totalBuscado, int contadorValoresRestantes, Items parcial);

Donde:
  • ptr apunta al elemento actual del vector
  • totalBuscado indica la suma que debemos localizar
  • contadorValoresRestantes indica cuántos elementos quedan por procesar del vector
  • parcial almacena la secuencia que estamos comprobando actualmente

Dado que lo que estamos pasando de forma recursiva es una combinación de elementos, parece buena idea usar una función de ayuda que sume los elementos de dicha combinación. Aunque sea una chorrada de función, mejor separar las cosas por claridad:

Código C++:
Ver original
  1. int suma(const Items& items)
  2. {
  3.   return std::accumulate(items.begin(),items.end(),0);
  4. }

Volviendo a la función recursiva, lo que hay que hacer es probar todas las combinaciones posibles, luego cada iteración tiene que probar las combinaciones con el número actual y sin el (en el ejemplo que has puesto, los resultados válidos pueden o no incorporar el primer elemento del vector, el 8). En el caso de que añada el número a la combinación basta con actualizar parcial.

Además, sabemos que si el parcial es superior al número buscado hay que abortar esa combinación puesto que sumar más valores no va a ayudar a encontrar un resultado bueno.

Con esto la función podría quedar así:

Código C++:
Ver original
  1. Resultado suma( int* ptr, int totalBuscado, int contadorValoresRestantes, Items parcial)
  2. {
  3.     Resultado resultado;
  4.  
  5.     contadorValoresRestantes--;
  6.     if( contadorValoresRestantes >= 0 )
  7.     {
  8.         // Probamos sin añadir el elemento actual
  9.         resultado = suma((ptr+1),totalBuscado,contadorValoresRestantes,parcial);
  10.     }
  11.  
  12.     // Probamos añadiendo el elemento actual
  13.     parcial.push_back(*ptr);
  14.     int total = suma(parcial);
  15.     if( (total < totalBuscado) && (contadorValoresRestantes >= 0) )
  16.     {
  17.         Resultado resultado2 = suma(++ptr,totalBuscado,contadorValoresRestantes,parcial);
  18.  
  19.         // Hay que fusionar ambos resultados
  20.         // Esta línea básicamente copia el contenido de resultado2 al final de resultado
  21.         resultado.insert(resultado.end(),resultado2.begin(),resultado2.end());
  22.     }
  23.     else if( total == totalBuscado )
  24.     {
  25.         // Si hemos encontrado una solución, la añadimos al resultado
  26.         resultado.push_back(parcial);
  27.     }
  28.  
  29.     return resultado;
  30. }

Ya está la función recursiva terminada.

Para simplificar su uso se puede hacer una función que haga las veces de entrada al algoritmo... quizás algo así:

Código C++:
Ver original
  1. Resultado suma( int* ptr, int numeroValores, int totalBuscado)
  2. {
  3.     return suma(ptr,totalBuscado,numeroValores-1,std::vector<int>());
  4. }

Y bueno, vamos a probar el código:

Código C++:
Ver original
  1. int main()
  2. {
  3.   const int SIZE = 6;
  4.   int Vector[SIZE] = {8,2,3,3,6,4}; //vector
  5.   Resultado resultados = suma(Vector,SIZE,13);
  6.  
  7.   std::cout << "Resultados: " << std::endl;
  8.   if( !resultados.empty() )
  9.   {
  10.     auto lambda = [&](const std::vector<int>& items)
  11.     {
  12.       std::string separador;
  13.       std::for_each(items.begin(),items.end(),[&](int v){ std::cout << separador << v; separador = ","; });
  14.       std::cout << std::endl;
  15.     };
  16.    
  17.     std::for_each(resultados.begin(),resultados.end(),lambda);
  18.   }
  19.   else
  20.     std::cout << "No hay resultados!!!" << std::endl;
  21. }

Lo que ofrece el siguiente resultado:

Código:
Resultados:
3,6,4
3,6,4
8,2,3
8,2,3
Vaya, los resultados aparecen duplicados. ¿Es un error? En absoluto. Lo que pasa es que hay dos elementos con valor 3, lo que arroja dos resultados distintos. Si quieres eliminar esos duplicados puedes optar por soluciones un poco más sofisticadas, una posibilidad es usar el contenedor set, pero eso tendrás que investigarlo un poco antes de que te ponga una respuesta :)

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.