Dada una lista de clasificaciones de jugadores, debo dividir a los jugadores (es decir, clasificaciones) en dos grupos de la manera más justa posible. El objetivo es minimizar la diferencia entre la calificación acumulativa de los equipos. No hay restricciones en cuanto a cómo puedo dividir a los jugadores en los equipos (un equipo puede tener 2 jugadores y el otro equipo puede tener 10 jugadores).
Por ejemplo: [5, 6, 2, 10, 2, 3, 4]
debería volver([6, 5, 3, 2], [10, 4, 2])
Me gustaría conocer el algoritmo para resolver este problema. Tenga en cuenta que estoy tomando un curso introductorio de programación en línea, por lo que se agradecerán los algoritmos simples.
Estoy usando el siguiente código, pero por alguna razón, el verificador de código en línea dice que es incorrecto.
def partition(ratings):
set1 = []
set2 =[]
sum_1 = 0
sum_2 = 0
for n in sorted(ratings, reverse=True):
if sum_1 < sum_2:
set1.append(n)
sum_1 = sum_1 + n
else:
set2.append(n)
sum_2 = sum_2 + n
return(set1, set2)
Actualización: Me puse en contacto con los instructores y me dijeron que debería definir otra función "auxiliar" dentro de la función para verificar todas las combinaciones diferentes, luego necesito verificar la diferencia mínima.
Respuestas:
Nota: Editado para manejar mejor el caso cuando la suma de todos los números es impar.
Retroceder es una posibilidad para este problema.
Permite examinar todas las posibilidades de forma recursiva, sin la necesidad de una gran cantidad de memoria.
Se detiene tan pronto como se encuentra una solución óptima:
sum = 0
dóndesum
está la diferencia entre la suma de los elementos del conjunto A y la suma de los elementos del conjunto B. EDITAR: se detiene tan prontosum < 2
para manejar el caso cuando la suma de todos los números es impar, es decir, corresponde a una diferencia mínima de 1. Si esta suma global es par, la diferencia mínima no puede ser igual a 1.Permite implementar un procedimiento simple de abandono prematuro :
en un momento dado, si
sum
es mayor que la suma de todos los elementos restantes (es decir, no colocados en A o B) más el valor absoluto del mínimo actual obtenido, entonces podemos dejar de examinar la ruta actual, sin examinar los elementos restantes. Este procedimiento está optimizado con:Aquí hay un pseudocódigo
Inicializacion:
a[]
sum_back[i] = sum_back[i+1] + a[i];
min_diff = sum_back[0];
a[0]
en A -> el índicei
del elemento examinado se establece en 1up_down = true;
: este valor booleano indica si actualmente estamos avanzando (verdadero) o retrocediendo (falso)Mientras bucle:
If (arriba_ abajo): adelante
sum_back
sum
según esta opciónif (i == n-1)
: LEAF -> prueba si se mejora el valor óptimo y devuelve si el nuevo valor es igual a 0 (EDITARif (... < 2)
); volver atrasIf (! Updown): hacia atrás
i == 0
: regresosum
valorAquí hay un código, en C ++ (lo siento, no sé Python)
fuente
if I == 0
. Lo probé reemplazando 10 por 11 en su ejemploCreo que deberías hacer el próximo ejercicio por tu cuenta, de lo contrario no aprenderás mucho. En cuanto a este, aquí hay una solución que intenta implementar el consejo de su instructor:
Salida:
Tenga en cuenta que esta salida es diferente de la deseada, pero ambas son correctas.
Este algoritmo se basa en el hecho de que, para elegir todos los subconjuntos posibles de un conjunto dado con N elementos, puede generar todos los enteros con N bits y seleccionar el elemento I-ésimo dependiendo del valor del bit I-ésimo. Dejo que agreguen un par de líneas para detenerse tan pronto como
best_distance
sea cero (porque, por supuesto, no puede mejorar).Un bit en bits (tenga en cuenta que
0b
es el prefijo para un número binario en Python):Un número binario:
0b0111001 == 0·2⁶+1·2⁵+1·2⁴+1·2³+0·2²+0·2¹+1·2⁰ == 57
Derecha desplazada por 1:
0b0111001 >> 1 == 0b011100 == 28
Izquierda desplazada por 1:
0b0111001 << 1 == 0b01110010 == 114
Derecha desplazada por 4:
0b0111001 >> 4 == 0b011 == 3
A nivel de bit
&
(y):0b00110 & 0b10101 == 0b00100
Para verificar si el quinto bit (índice 4) es 1:
(0b0111001 >> 4) & 1 == 0b011 & 1 == 1
Uno seguido de 7 ceros:
1 << 7 == 0b10000000
7 unos:
(1 << 7) - 1 == 0b10000000 - 1 == 0b1111111
Todas las combinaciones de 3 bits:
0b000==0
,0b001==1
,0b010==2
,0b011==3
,0b100==4
,0b101==5
,0b110==6
,0b111==7
(nota que0b111 + 1 == 0b1000 == 1 << 3
)fuente
El siguiente algoritmo hace esto:
a
, impares en la listab
para comenzara
yb
si el cambio es para mejorHe agregado declaraciones impresas para mostrar el progreso en su lista de ejemplos:
Salida:
fuente
Como sé que tengo que generar todas las listas posibles, necesito hacer una función de "ayuda" para ayudar a generar todas las posibilidades. Después de hacer eso, debo verificar la diferencia mínima, y la combinación de listas con esa diferencia mínima es la solución deseada.
La función auxiliar es recursiva y verifica todas las posibilidades de combinaciones de listas.
Ejemplos:
r = [1, 2, 2, 3, 5, 4, 2, 4, 5, 5, 2]
la partición óptima sería:([1, 2, 2, 3, 5, 4], [2, 4, 5, 5, 2])
con una diferencia de1
.r = [73, 7, 44, 21, 43, 42, 92, 88, 82, 70]
, la partición óptima sería:([73, 7, 21, 92, 88], [44, 43, 42, 82, 70])
con una diferencia de0
.fuente
Aquí hay un ejemplo bastante elaborado, destinado a fines educativos en lugar de desempeño. Introduce algunos conceptos interesantes de Python, como las listas de comprensiones y generadores, así como un buen ejemplo de recursión en el que los casos marginales deben verificarse adecuadamente. Las extensiones, por ejemplo, solo los equipos con el mismo número de jugadores son válidos, son fáciles de implementar en las funciones individuales apropiadas.
Salida:
fuente
Dado que quiere incluso equipos, conoce el puntaje objetivo de las calificaciones de cada equipo. Esta es la suma de las calificaciones dividida por 2.
Entonces, el siguiente código debe hacer lo que quieras.
Salida
Hay otras divisiones que tienen lo mismo
fairness
, todas están disponibles para encontrar dentro de la tupla strong_ratings, solo elijo mirar la primera, ya que esto siempre existirá para cualquier lista de calificaciones que ingrese (provistalen(ratings) > 1
).fuente
Una solución codiciosa podría producir una solución subóptima. Aquí hay una solución codiciosa bastante simple, la idea es ordenar la lista en orden descendente para disminuir el efecto de la adición de calificaciones en el cubo. La calificación se agregará a ese grupo cuya suma total de calificación es menor
Salida:
Editar:
Otro enfoque será generar todos los subconjuntos posibles de la lista. Digamos que tiene l1, que es uno de los subconjuntos de la lista, entonces puede obtener fácilmente la lista l2 de modo que l2 = lista (original) - l1. El número de todos los subconjuntos posibles de la lista de tamaño n es 2 ^ n. Podemos denotarlos como seq de un entero de 0 a 2 ^ n -1. Tome un ejemplo, digamos que tiene una lista = [1, 3, 5], entonces ninguna combinación posible es 2 ^ 3, es decir, 8. Ahora podemos escribir todas las combinaciones de la siguiente manera:
Solución:
Salida:
fuente