Dada uma lista de classificações de jogadores, sou obrigado a dividir os jogadores (ou seja, classificações) em dois grupos o mais razoavelmente possível. O objetivo é minimizar a diferença entre a classificação acumulada das equipes. Não há restrições sobre como posso dividir os jogadores em equipes (uma equipe pode ter 2 jogadores e a outra equipe pode ter 10 jogadores).
Por exemplo: [5, 6, 2, 10, 2, 3, 4]
deve retornar([6, 5, 3, 2], [10, 4, 2])
Gostaria de conhecer o algoritmo para resolver este problema. Observe que estou fazendo um curso introdutório de programação on-line, para que algoritmos simples sejam apreciados.
Estou usando o código a seguir, mas, por algum motivo, o verificador de código on-line diz que está incorreto.
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)
Atualização: entrei em contato com os instrutores e me disseram que eu deveria definir outra função "auxiliar" dentro da função para verificar todas as combinações diferentes; então, preciso verificar a diferença mínima.
Respostas:
Nota: Editado para lidar melhor com o caso quando a soma de todos os números é ímpar.
O retorno é uma possibilidade para esse problema.
Permite examinar todas as possibilidades recursivamente, sem a necessidade de uma grande quantidade de memória.
Para assim que uma solução ótima é encontrada:,
sum = 0
ondesum
está a diferença entre a soma dos elementos do conjunto A e a soma dos elementos do conjunto B. EDIT: ele pára assim quesum < 2
, para lidar com o caso quando a soma de todos os números é ímpar, ou seja, corresponde a uma diferença mínima de 1. Se essa soma global for par, a diferença mínima não poderá ser igual a 1.Permite implementar um procedimento simples de abandono prematuro :
em um determinado momento, se
sum
for maior que a soma de todos os elementos restantes (ou seja, não colocados em A ou B) mais o valor absoluto do mínimo atual obtido, podemos deixar de examinar o caminho atual, sem examinar os elementos restantes. Este procedimento é otimizado com:Aqui está um pseudo-código
Inicialização:
a[]
sum_back[i] = sum_back[i+1] + a[i];
min_diff = sum_back[0];
a[0]
em A -> o índicei
do elemento examinado é definido como 1up_down = true;
: este booleano indica se estamos atualmente avançando (true) ou backward (false)Enquanto loop:
Se (up_down): encaminhar
sum_back
sum
acordo com esta escolhaif (i == n-1)
: LEAF -> teste se o valor ideal é aprimorado e retorne se o novo valor for igual a 0 (EDIT:if (... < 2)
; ir para trásIf (! Updown): para trás
i == 0
: returnsum
valorAqui está um código, em C ++ (Desculpe, não sei Python)
fonte
if I == 0
. Eu testei substituindo 10 por 11 no seu exemploEu acho que você deve fazer o próximo exercício sozinho, caso contrário você não aprenderá muito. Quanto a este, aqui está uma solução que tenta implementar o conselho do seu instrutor:
Resultado:
Observe que essa saída é diferente da desejada, mas ambas estão corretas.
Esse algoritmo é baseado no fato de que, para selecionar todos os subconjuntos possíveis de um determinado conjunto com N elementos, você pode gerar todos os números inteiros com N bits e selecionar o item I-ésimo, dependendo do valor do I-ésimo bit. Deixo para você adicionar algumas linhas para parar assim que o
best_distance
zero for zero (porque não pode melhorar, é claro).Um pouco sobre bits (observe que
0b
é o prefixo de um número binário em Python):Um número binário:
0b0111001 == 0·2⁶+1·2⁵+1·2⁴+1·2³+0·2²+0·2¹+1·2⁰ == 57
Deslocado para a direita em 1:
0b0111001 >> 1 == 0b011100 == 28
Deslocado para a esquerda em 1:
0b0111001 << 1 == 0b01110010 == 114
Deslocado para a direita em 4:
0b0111001 >> 4 == 0b011 == 3
Bit a bit
&
(e):0b00110 & 0b10101 == 0b00100
Para verificar se o quinto bit (índice 4) é 1:
(0b0111001 >> 4) & 1 == 0b011 & 1 == 1
Um seguido por 7 zeros:
1 << 7 == 0b10000000
7 ones:
(1 << 7) - 1 == 0b10000000 - 1 == 0b1111111
Todas as combinações de três bits:
0b000==0
,0b001==1
,0b010==2
,0b011==3
,0b100==4
,0b101==5
,0b110==6
,0b111==7
(note que0b111 + 1 == 0b1000 == 1 << 3
)fonte
O seguinte algoritmo faz isso:
a
, ímpares na listab
para iniciara
eb
se a alteração é para melhorEu adicionei instruções de impressão para mostrar o progresso em sua lista de exemplos:
Resultado:
fonte
Como sei que tenho que gerar todas as listas possíveis, preciso criar uma função "auxiliar" para ajudar a gerar todas as possibilidades. Depois disso, verifiquei a diferença mínima e a combinação de listas com essa diferença mínima é a solução desejada.
A função auxiliar é recursiva e verifique todas as possibilidades de combinações de listas.
Exemplos
r = [1, 2, 2, 3, 5, 4, 2, 4, 5, 5, 2]
:, a partição ideal seria:([1, 2, 2, 3, 5, 4], [2, 4, 5, 5, 2])
com uma diferença de1
.r = [73, 7, 44, 21, 43, 42, 92, 88, 82, 70]
, a partição ideal seria:([73, 7, 21, 92, 88], [44, 43, 42, 82, 70])
com uma diferença de0
.fonte
Aqui está um exemplo bastante elaborado, destinado a fins educacionais e não a desempenho. Ele apresenta alguns conceitos interessantes do Python, como compreensão de lista e geradores, bem como um bom exemplo de recursão em que casos adicionais precisam ser verificados adequadamente. Extensões, por exemplo, apenas equipes com um número igual de jogadores são válidas, são fáceis de implementar nas funções individuais apropriadas.
Resultado:
fonte
Dado que você quer equipes iguais, você conhece a pontuação desejada das classificações de cada equipe. Esta é a soma das classificações divididas por 2.
Portanto, o código a seguir deve fazer o que você deseja.
Resultado
Existem outras divisões com as mesmas,
fairness
todas disponíveis para encontrar dentro da tupla strong_ratings, apenas optei por ver a primeira, pois ela sempre existirá para qualquer lista de classificações que você passar (desdelen(ratings) > 1
).fonte
Uma solução gananciosa pode gerar uma solução abaixo do ideal. Aqui está uma solução gananciosa bastante simples, a idéia é classificar a lista em ordem decrescente para diminuir o efeito da adição de classificações no intervalo. A classificação será adicionada ao intervalo cuja soma total da classificação é menor
Resultado :
Editar:
Outra abordagem será gerar todos os subconjuntos possíveis da lista. Digamos que você tenha l1, que é um dos subconjuntos da lista, e é possível obter facilmente a lista l2 de forma que l2 = list (original) - l1. O número de todo o subconjunto possível da lista de tamanho n é 2 ^ n. Podemos denotá-los como seq de um número inteiro de 0 a 2 ^ n -1. Tomemos um exemplo, digamos que você tenha list = [1, 3, 5], então nenhuma das combinações possíveis é 2 ^ 3, ou seja, 8. Agora, podemos escrever todas as combinações da seguinte maneira:
Solução:
Resultado :
fonte