Hay varias maneras de resolver este problema. Una es la clásica solución DP que otros han publicado.Voy a publicar una solución que usa solo memoria O (S), donde S es la suma de todos los enteros en la matriz (se puede cambiar para significar la suma deseada también) y otra que usa un algoritmo aleatorizado muy eficiente que puede ser probado para ser muy rápido incluso para cientos de miles de números de cualquier tamaño, e incluso números racionales y negativos.
solución de DP en tiempo O (NS) y la memoria O (S):
//let F[i] = 1 if we can get sum i and 0 otherwise
F[0] = 1; // we can always make sum 0
for (int i = 1; i <= n; ++i)
for (int j = S; j >= numbers[i]; --j)
F[j] |= F[j - numbers[i]]; // basically, if F[j - numbers[i]] == 1, then we
// can add numbers[i] to make F[j] 1, otherwise
// we can't. A bitwise or operation will save us
// an if/else structure basically.
Pseudocódigo para el algoritmo aleatorio: Let utilizadas = lista de números a los que suma. Let Unused = lista de números que NO sumas. Dejar tmpsum = 0. Deje que S = suma deseada que desea alcanzar.
for (each number x you read)
toss a coin:
if it's heads and tmpsum < S
add x to Used
else
add x to Unused
while (tmpsum != S)
if tmpsum < S
MOVE one random number from Unused to Used
else
MOVE one random number from Used to Unused
print the Used list, containing the numbers you need to add to get S
Esto será mucho más rápido que la solución de programación dinámica, especialmente para las entradas aleatorias. Los únicos problemas son que no puede detectar de manera confiable cuando no hay solución (puede dejar que el algoritmo se ejecute durante unos segundos y, si no termina, asumir que no hay solución) y que no puede estar seguro de que obtendrá la solución con el mínimo número de elementos elegidos. De nuevo, podría agregar algo de lógica para hacer que el algoritmo continúe e intente encontrar una solución con menos elementos hasta que se cumplan ciertas condiciones de detención, pero esto lo hará más lento. Sin embargo, si solo está interesado en una solución que funciona y tiene MUCHOS números y la suma deseada puede ser MUY grande, probablemente sea mejor que el algoritmo DP.
Otra ventaja de este enfoque es que también funcionará para números negativos y racionales sin modificaciones, lo que no es cierto para la solución DP, porque la solución DP implica el uso de sumas parciales como índices de matriz, y los índices solo pueden ser números naturales. Por supuesto, puede usar hashtables, pero eso hará que la solución DP sea aún más lenta.
para generar todas las combinaciones, usted debe mirar hacia arriba dando marcha atrás: http://en.wikipedia.org/wiki/Backtracking
Para este problema, es necesario utilizar algo como esto:
void back(int k)
{
if (k > numElements)
{
// add all the nums[i] for which st[i] == 1 and check
// if their sum is what you desire, then return;
}
for (int i = 0; i <= 1; ++i)
{
st[k] = i;
back(k + 1);
}
}
debería ejecutar en un papel de pequeño número de elementos para ver cómo funciona Puede optimizarlo calculando la suma sobre la marcha, evitando así la suma final. Esta es la idea general.
C++, si es de hecho una matriz (y no un 'std :: set':' std :: next_permutation'. ':)' – sbi
sbi, ¿cómo ayuda eso con una pregunta de algoritmo? –
@sbi: eso es casi completamente inútil. Te da todo n! posibles órdenes del conjunto, pero dado que la suma es conmutativa y asociativa, todas esas órdenes tienen la misma suma de todos modos. Waldrop está tratando de resolver un relativo del problema de la suma del subconjunto, así que para usarlo como fuerza bruta necesita iterar sobre los subconjuntos 2^n. –