Cómo buscar todas las combinaciones posibles en una lista

No es posible hacerlo mejor que enumerar todas las combinaciones posibles, en el peor de los casos, porque todas ellas podrían satisfacer el límite T = 0, y todos menos uno satisfacen el elemento límite T = más pequeño. ¿Pero hay un límite en “T” (la suma mínima de la combinación) para el cual el problema se vuelve más fácil? Asumamos que los elementos son todos positivos.

Supongamos que T está muy cerca de la suma de todos los elementos del conjunto. Entonces no necesitamos considerar todos los subconjuntos pequeños, ya que ninguno de ellos será lo suficientemente grande. Por ejemplo, si la entrada es {10, 11, 12, 13, 14, 15} y T = 60, entonces solo 6 de los subconjuntos posibles [matemáticas] 2 ^ 6 [/ matemáticas] son ​​lo suficientemente grandes (omita uno de los números, o ninguno de ellos.)

Esto sugiere que busquemos las combinaciones comenzando con el mayor número de elementos elegidos, pasando a subconjuntos más pequeños y abandonemos siempre que ningún subconjunto de tamaño K sea lo suficientemente grande. Otra optimización, si hay un solo elemento grande que debe estar en el conjunto, es reducir a un tamaño de problema más pequeño al incluir siempre ese elemento, o eliminar de manera equivalente ese elemento y restar su valor de T. Esto puede ayudar a hacer la búsqueda terminar temprano

Desafortunadamente, si bien el orden de búsqueda de subconjunto de mayor a menor puede ser útil en la práctica, no cambia sustancialmente el tiempo de ejecución máximo. Si tenemos que buscar desde el tamaño del subconjunto K = N hasta K = N / 2, todavía hemos observado la mitad de las combinaciones posibles, solo una mejora de factor constante. Se debe garantizar que los elementos de la lista se distribuyan de manera relativamente uniforme, como en el ejemplo anterior, para lograr una aceleración más que fraccional. Por ejemplo, si podemos garantizar que solo los conjuntos con elementos N-3 o más satisfacen la restricción, entonces [matemáticas] {N \ elegir N-3} + {N \ elegir N-2} + {N \ elegir N-1 } + 1 = O (N ^ 3) [/ math] Simplemente tener una T grande no es suficiente si unos pocos elementos del conjunto pueden satisfacerla.

Dado que potencialmente hay muchos subconjuntos para buscar, no hay forma de hacerlo más rápido que el tiempo exponencial.

El método más fácil es enumerar todos los subconjuntos en orden. Esto se puede hacer contando y seleccionando los elementos en las posiciones correspondientes a 1 bit en el contador. Eche un vistazo al código que utilicé en esta respuesta para seleccionar los signos de coeficientes para un ejemplo: la respuesta de David Rutter a ¿Cuáles son, asintóticamente, las raíces racionales más comunes de polinomios de coeficiente entero?

Puede acelerar este algoritmo asegurándose de que está seleccionando de un conjunto, no solo de una lista. En otras palabras, todos los valores involucrados deben ser únicos.

También puede contar en un orden diferente: observe los subconjuntos de tamaño 1, luego 2, luego 3, etc. Esto es más difícil de implementar pero permite un ahorro de tiempo significativo, ya que puede ordenar los elementos y asegurarse de comenzar por incluido el elemento más pequeño que debe incluirse para garantizar que la suma sea lo suficientemente grande como para que varios elementos alcancen la suma requerida. No obstante, el algoritmo aún requiere un tiempo exponencial en el peor de los casos.

A2A

Esto se puede resolver usando en retroceso. En general, el problema requiere que encontremos todas las combinaciones posibles [matemáticas] k [/ matemáticas] de un conjunto de elementos [matemáticas] n [/ matemáticas].

Considere todas las combinaciones de longitud [math] k [/ math] que comienzan en [math] i [/ math], podemos construir esto iterativamente usando una matriz temporal hasta que el tamaño de la matriz sea hasta [math] k [/ math ]

A continuación se muestra un código de muestra.

Solución de clase pública {
public List > combine (int n, int k) {

List > A = new ArrayList <> ();
si (n List tmp = new ArrayList <> ();
int [] v = nuevo int [n + 1];
resolver (A, tmp, v, k, 1);
devolver A;
}
vacío resolver (List > A, List tmp, int [] v, int k, int index) {

int n = v.length-1;

if (tmp.size () == k) {
List cop = new ArrayList <> ();
para (Entero y: tmp) cop.add (y);
A.add (policía);
regreso;
}

for (int i = index; i <= n; i ++) {

if (v [i] == 0) {
tmp.add (i);
v [i] = 1;
resolver (A, tmp, v, k, i + 1);
tmp.remove (tmp.size () – 1);
v [i] = 0;
}
}
}
}

La forma más rápida que conozco para obtener un conjunto de potencia es el conteo binario: cuente de 0 a elementos de número en el conjunto-1 con ceros a la izquierda para que cada número binario tenga el número de bins que para cada número binario si su bit k es 1, incluya el k elemento en el subconjunto que construye y este desafortunado es una complejidad exponencial.

Sin embargo, podemos acortar nuestra cantidad de trabajo, si la lista es bastante larga, dará sus frutos:

Primero verifique si la suma de la lista es de hecho mayor que su valor t, si no, entonces no tiene resultados si es así, clasifique [1] la lista, pero recuerde las posiciones originales de los elementos (la lista ordenada es una lista de pares con este aspecto ([value = value1, position = position_of_value1_in_original_list], [value = value2, position = position_of_value2_in_original_list], [value = value3, position = position_of_value3_in_original_list], …)) que con una búsqueda binaria [2] encuentre el elemento más pequeño e en la lista ordenada de manera tal que [math] e _ {\ text {value}} \ ge t [/ math], que compruebe si [math] \ sum \ limits_ {k = 0} ^ {\ text {posición de e en la lista ordenada -1}} \ text {led_list_values} [k] \ ge t [/ math] si no ha terminado, tome el conjunto de potencia de todos los elementos de la lista ordenada ue tal que [math] ue _ {\ text {value}} \ lt e _ {\ text {value}} [/ math] y combínelos con el conjunto de poder de los elementos de la lista ordenada ae tal que [math] ae _ {\ text {value}} \ ge e _ {\ text {value}} [/matemáticas]

en caso afirmativo, elimine el último elemento de ue (es el más grande) hasta que la suma de ue sea menor que t que tomar todas las combinaciones de ue eqaul t más grande y agregarlas a ae.

Notas al pie

[1] Algoritmo de clasificación – Wikipedia

[2] Algoritmo de búsqueda binaria – Wikipedia

More Interesting

¿Cuál es el algoritmo utilizado para llenar el tablero en el juego Bejeweled Blitz?

Cómo implementar un algoritmo de programación de disco C-SCAN para encontrar su tiempo de búsqueda

¿Son los algoritmos genéticos en sí mismos una forma de inteligencia artificial?

¿Los ingenieros de software de Google, Amazon, etc. utilizan estructuras de datos y algoritmos en el desarrollo de aplicaciones en tiempo real?

¿El mismo algoritmo pertenece a algo, incluyendo política, mecánica cuántica, arte, deportes e ingeniería?

¿Cuál es el algoritmo más eficiente y efectivo para la detección de anomalías / valores atípicos cuando los datos tienen un pico / valle estacional?

¿Cuál sería la mejor estrategia de negociación algorítmica simple?

¿Qué bases de datos tienen implementaciones muy eficientes de estructuras de datos de índice R-Tree?

¿Cuál es el programa de clasificación rápida que tiene su mediana como pivote?

¿Son los métodos en algoritmos Java?

¿Cuáles son algunos de sus mejores algoritmos de C ++ o C que está orgulloso de haber escrito?

¿Cómo puede una persona que no está en el mundo académico presentar pruebas correctas de que NP = O (n), la jerarquía polinómica se colapsa y existe un algoritmo eficiente de O (n) para resolver cualquier problema sin causar caos y pánico masivo porque se rompería todo el cifrado?

¿Cuáles son las ventajas de los diferentes algoritmos de clasificación?

Como senior que busca postularse a empresas como Google, Palantir, etc., ¿cómo puedo mejorar mis estructuras de datos avanzadas, algoritmos y cursos de bioinformática y tener más confianza en mí mismo al ingresar a un aula y no pensar automáticamente que soy estúpido? ?

¿Siempre es bueno tener una solución recursiva que una solución iterativa?