Dado:
- Um número natural S .
- Uma lista de N pesos racionais W que somam 1.
Retorne uma lista L de N números inteiros não negativos, de modo que:
(1) sum(L) = S
(2) sum((S⋅W_i - L_i)^2) is minimal
Em outras palavras, aproxime S⋅W_i
s com números inteiros o mais próximo possível.
Exemplos:
1 [0.4 0.3 0.3] = [1 0 0]
3 [0 1 0] = [0 3 0]
4 [0.3 0.4 0.3] = [1 2 1]
5 [0.3 0.4 0.3] = [2 2 1] or [1 2 2] but not [1 3 1]
21 [0.3 0.2 0.5] = [6 4 11]
5 [0.1 0.2 0.3 0.4] = [1 1 1 2] or [0 1 2 2]
4 [0.11 0.3 0.59] = [1 1 2]
10 [0.47 0.47 0.06] = [5 5 0]
10 [0.43 0.43 0.14] = [4 4 2]
11 [0.43 0.43 0.14] = [5 5 1]
Regras:
- Você pode usar qualquer formato de entrada ou apenas fornecer uma função que aceite a entrada como argumentos.
Fundo:
Esse problema surge ao exibir S de diferentes tipos de itens em diferentes proporções W i com relação aos tipos.
Outro exemplo desse problema é a representação política proporcional, veja o paradoxo da repartição . Os dois últimos casos de teste são conhecidos como paradoxo do Alabama.
Como estatístico, reconheci esse problema como equivalente a um problema encontrado na identificação de tamanhos de amostras ao conduzir uma amostra estratificada. Nessa situação, queremos tornar a proporção de cada estrato na amostra igual à proporção de cada estrato na população. - @tomi
fonte
round(A + B) != round(A) + round(B)
, uma solução curta requer uma visão do que está acontecendo aqui.L[i] - S*W[i]
ao quadrado, em vez da regra 2 e da regra 3. Isso seria aproximadoS*W[i]
.[0 1 2 2]
é outra solução possível para5 [0.1 0.2 0.3 0.4]
Respostas:
APL, 21
Esta é uma tradução da resposta CJam de 37 bytes do aditsu .
Teste online .
Explicação
fonte
Python 2,
9583132125143Meu primeiro (e segundo) (e terceiro) algoritmo teve problemas e, após uma (outra!) Reescrita e mais testes, aqui está (eu realmente espero) uma solução correta e rápida:
A fonte antes do minificador agora se parece com:
Os testes retornam:
Este algoritmo é semelhante a outras respostas aqui. É O (1) para num, portanto, tem o mesmo tempo de execução para os números 10 e 1000000. Teoricamente, é O (nlogn) para o número de pesos (por causa da classificação). Se isso suportar todos os outros casos de entrada complicados, ele substituirá o algoritmo abaixo na minha caixa de ferramentas de programação.
Por favor, não use esse algoritmo com nada que não seja golfe. Fiz concessões na velocidade para minimizar o tamanho da fonte. O código a seguir usa a mesma lógica, mas é muito mais rápido e mais útil:
O valor de num não afeta significativamente a velocidade. Eu testei com valores de 1 a 10 ^ 19. O tempo de execução varia linearmente com o número de pesos. No meu computador, são necessários 0,15 segundo com 10 ^ 5 pesos e 15 segundos com 10 ^ 7 pesos. Observe que os pesos não estão restritos a frações que somam um. A técnica de classificação usada aqui também é duas vezes mais rápida que o
sorted((v,i) for i,v in enumerate...)
estilo tradicional .Algoritmo Original
Esta foi uma função na minha caixa de ferramentas, modificada um pouco para o golfe. Foi originalmente de uma resposta SO . E está errado.
Ele fornece uma aproximação, mas nem sempre é correto, embora a soma (outseq) == num seja mantida. Rápido, mas não recomendado.
Agradecemos a @alephalpha e @ user23013 por detectar os erros.
EDIT: Defina o totalw (d) como 1, pois OP especifica que a soma dos pesos será sempre 1. Agora, 83 bytes.
EDIT2: Corrigido o erro encontrado para [0,4, 0,3, 0,3], 1.
EDIT3: algoritmo defeituoso abandonado. Adicionado melhor.
EDIT4: Isso está ficando ridículo. Substituído pelo algoritmo correto (eu realmente espero que sim).
EDIT5: Adicionado código não-golfy para outras pessoas que desejam usar esse algoritmo.
fonte
a([0.4, 0.3, 0.3], 1)
retorna[0, 1, 0]
, enquanto a resposta correta é[1, 0, 0]
.a([0.11,0.3,0.59],4)
retornado[0, 1, 3]
. Deveria ser[1, 1, 2]
.f([0.47,0.47,0.06],10)
retornado[5, 4, 1]
. Deveria ser[5, 5, 0]
.Mathematica,
67504645 caracteresUngolfed:
Exemplo:
fonte
CJam - 37
Experimente online
Explicação:
Notas:
Idéia diferente - 46
Experimente online
Isso é muito mais direto e eficiente, mas, infelizmente, um pouco mais. A idéia aqui é começar com L_i = piso (S * W_i), determinar a diferença (digamos D) entre S e sua soma, encontrar os índices D com a maior parte fracionária de S * W_i (classificando e tomando D superior) e incremente L_i para esses índices. Complexidade O (N * log (N)).
fonte
:e<
.JavaScript (ES6) 126
130 104 115 156 162 194Depois de todos os comentários e casos de teste na resposta do @ CarpetPython, voltemos ao meu primeiro algoritmo. Infelizmente, a solução inteligente não funciona. A implementação encurtou um pouco, ainda tenta todas as soluções possíveis, calcula a distância ao quadrado e mantém o mínimo.
Editar Para cada elemento de saída com peso w, 'todos' os valores possíveis são apenas 2: trunc (w * s) e trunc (w * s) +1, portanto, existem apenas (2 ** elemensts) soluções possíveis para tentar.
Teste no console Firefox / FireBug
Resultado
Essa é uma solução mais inteligente. Passagem única na matriz de peso.Para cada passagem, encontro o valor máximo atual em w. Eu mudo esse valor no lugar com o valor inteiro ponderado (arredondado para cima), portanto, se s == 21 ew = 0,4, obtemos 0,5 * 21 -> 10,5 -> 11. Eu armazeno esse valor negado, por isso não pode seja encontrado como max no próximo loop. Então, reduzo a soma total de acordo (s = s-11) e também reduzo o total de pesos na variável f.
O loop termina quando não há um máximo acima de 0 a ser encontrado (todos os valores! = 0 foram gerenciados).
Por fim, retorno os valores alterados para positivo novamente. Aviso: este código modifica a matriz de pesos no local, portanto deve ser chamada com uma cópia da matriz original
Minha primeira tentativa
Não é uma solução inteligente. Para cada resultado possível, avalia a diferença e mantém o mínimo.
Ungolfed And Explained
fonte
CJam, 48 bytes
Uma solução direta para o problema.
A entrada é como
Explicação:
Experimente online aqui
fonte
Pitão: 40 bytes
Isso define uma função
g
com 2 parâmetros. Você pode chamar assimMhosm^-*Ghded2C,HNfqsTGmms+*G@Hb}bklHyUHg5 [0.1 0.2 0.3 0.4
.Experimente online: Pyth Compiler / Executor
Explicação:
Isso cria todas as soluções possíveis
L
, ondeL[i] = floor(S*W[i])
ouL[i] = floor(S*W[i]+1)
. Por exemplo, a entrada4 [0.3 0.4 0.3
cria[[1, 1, 1], [2, 1, 1], [1, 2, 1], [1, 1, 2], [2, 2, 1], [2, 1, 2], [1, 2, 2], [2, 2, 2]]
.Apenas
[[2, 1, 1], [1, 2, 1], [1, 1, 2]]
permaneça.fonte
Mathematica 108
Explicação
Ungolfed
IntegerPartitions[s,{Length@w},0~Range~s]
retorna todas as partições inteiras des
, usando elementos retirados do conjunto{0, 1, 2, ...s}
com a restrição de que a saída deve conter o mesmo número de elementos que o conjunto de pesosw
,.Permutations
fornece todas as disposições ordenadas de cada partição inteira.{Tr[(s *w-#)^2],#}
retorna uma lista de pares ordenados,{error, permutation}
para cada permutação.Sort[...]
classifica a lista de{{error1, permutation1},{error2, permutation2}...according to the size of the error.
[[1,2]]]
ouPart[<list>,{1,2}]
retorna o segundo item do primeiro elemento na lista classificada de{{error, permutation}...}
. Em outras palavras, ele retorna a permutação com o menor erro.fonte
R,
858076Usa o método Hare Quota.
Removemos um casal depois de ver a especificação que W somará 1
Execução de teste
fonte
Python,
139128117 bytesSolução de itertools anterior, 139 bytes
fonte
O(S^len(W))
na verdade: P. Nova solução é muito mais rápida, mas ainda lentaOitava,
8776Golfe:
Ungolfed:
(Blasted "endfor" e "endfunction"! Eu nunca vencerei, mas gosto de jogar golfe com uma linguagem "real".)
fonte
zeros(size(w))
por0*w
.T-SQL,
167265Porque eu gosto de tentar fazer esses desafios em uma consulta também.
Transformado em uma função embutida para melhor ajustar a especificação e criou um tipo para os dados da tabela. Custou um pouco, mas isso nunca seria um candidato. Cada instrução precisa ser executada separadamente.
Em uso
fonte