Introdução
Em uma eleição geral, alguém gostaria de calcular um preço constante por assento no parlamento. Isso significa que, para N >= 0
distribuir assentos e uma lista ns
de votos por partido, gostaríamos de encontrar um número d
tal que
sum(floor(n/d) for n in ns) == N
Para tornar as coisas interessantes (e mais parecidas com o mundo real), adicionamos mais dois fatos:
Dois partidos podem se reunir em uma 'coalizão', de modo que os assentos sejam dados à 'coalizão' pela soma dos votos para todos os partidos nela. Em seguida, os assentos que a 'coalizão' obteve são divididos entre os partidos de maneira semelhante (encontre divisor, etc.)
Um partido que não aprovou uma certa porcentagem dos votos (por exemplo, 3,25%) obtém automaticamente 0 assentos, e seus votos não contam para uma 'coalizão'.
Desafio
Você recebe:
- Uma lista de listas, cada uma das listas aninhadas, contém números inteiros (número de votos) e tem o comprimento 1 para um único partido ou o comprimento 2 para uma 'coalizão'.
- Porcentagem mínima de votos (também conhecida como "barra" para "barragem") para obter assentos, como uma fração (portanto, 3,25% é dado como 0,0325)
- Número total de assentos a serem distribuídos entre todas as partes (número inteiro)
Você deve imprimir a mesma estrutura de lista aninhada, com o número de votos substituído por cadeiras no parlamento.
Vencedor é o código com a menor quantidade de bytes.
Caixas de canto:
- Pode haver (e geralmente haverá) mais de um divisor possível. Como não está na saída, isso realmente não importa.
- Imagine
N=10
ens = [[1]]
, portanto, o divisor pode ser 0,1 (não um número inteiro) - Alguns casos não podem ser resolvidos, por exemplo
ns=[[30],[30],[100]]
,bar=0
,N=20
. Há um limite com od=7.5
qual a soma dos valores com base salta de 19 para 21. Não é esperado que você resolva esses casos. (obrigado ao membro da comunidade Arnauld por apontar este caso)
Exemplo de entrada e saída
Um exemplo muito otimizado do Python3:
from math import floor
def main(_l, bar, N):
# sum all votes to calculate bar in votes
votes = sum(sum(_) for _ in _l)
# nullify all parties that didn't pass the bar
_l = [[__ if __ >= bar * votes else 0 for __ in _] for _ in _l]
# find divisor for all parliament seats
divisor = find_divisor([sum(_) for _ in _l], N)
# find divisor for each 'coalition'
divisors = [find_divisor(_, floor(sum(_)/divisor)) for _ in _l]
# return final results
return [[floor(___/_) for ___ in __] for _, __ in zip(divisors, _l)]
def find_divisor(_l, N, _min=0, _max=1):
s = sum(floor(_ / _max) for _ in _l)
if s == N:
return _max
elif s < N:
return find_divisor(_l, N, _min, (_max + _min) / 2)
else:
return find_divisor(_l, N, _max, _max * 2)
print(main(l, bar, N))
Exemplo de entrada:
l = [[190970, 156473],
[138598, 173004],
[143666, 193442],
[1140370, 159468],
[258275, 249049],
[624, 819],
[1125881],
[152756],
[118031],
[74701]]
bar = 0.0325
N = 120
E sua saída:
[[6, 4], [0, 5], [4, 6], [35, 5], [8, 8], [0, 0], [35], [4], [0], [0]]
Mais alguns exemplos de saídas:
Se bar=0.1
obtivermos um impasse interessante entre duas partes, uma vez que nenhuma das partes menores é contada:
[[0, 0], [0, 0], [0, 0], [60, 0], [0, 0], [0, 0], [60], [0], [0], [0]]
E se N=0
(canto), é claro que ninguém recebe nada:
[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0], [0], [0], [0]]
d=7.5
você salta de 19 para 21 assentos.Respostas:
05AB1E ,
4239 bytesExperimente online!
05AB1E não possui boa recursão, portanto, implementar uma pesquisa binária como no código de referência seria doloroso. Felizmente, não precisamos encontrar o divisor!
Vamos usar um exemplo simples: [600, 379, 12, 9] votos, 100 assentos, nenhuma coalizão, nenhuma barra. Primeiro, calculamos quantos assentos fracionários cada parte obtém, definindo assentos fracionados como
party_votes * seats / sum_of_votes
. No nosso exemplo, isso gera [60, 37,9, 1,2, 0,9].O interessante é que, se uma festa conseguir
f
assentos fracionários, terá assentos iguaisint(f)
ouint(f) + 1
reais. Isso significa que já sabemos como 60 + 37 + 1 = 98 dos assentos serão alocados e ficamos com 2 "assentos de bônus" para distribuir entre as quatro partes (nenhuma das partes pode obter mais de um assento de bônus). A quem esses assentos de bônus vão? As partes com a maior proporção def / (int(f) + 1)
(prova deixada como exercício para o leitor). Em nossos exemplos, as proporções são[0.98, 0.997, 0.6, 0.9]
, portanto, as duas primeiras partes recebem um assento de bônus cada.Vamos dar uma olhada no código. Primeiro, substituímos a contagem de votos de todas as partes que não atenderam à ordem por 0:
Agora, para contornar a falta de recursão, usamos um awkard
2F
para repetir o código principal duas vezes. No primeiro passo, distribuirá o total de assentos entre a coalizão e, no segundo, distribuirá os assentos de cada coalizão entre seus partidos. Como o primeiro passe é executado apenas uma vez, mas o segundo passa para cada coalizão, isso envolve bastante trabalho ocupado.Ok, depois desse pedaço obscuro, o topo da pilha agora é uma lista de votos (votos da coalizão no primeiro passe, votos dos partidos no segundo), e abaixo desse número está o número de assentos a serem alocados. Usamos isso para calcular a lista de assentos fracionários:
Agora, calculamos as proporções:
Bitwise não funciona lindamente, aqui. Ele trunca para inteiro, adiciona 1 e nega, tudo em um único byte. Por que negar? Em 05AB1E, a divisão por 0 retorna 0, e precisamos deles para classificar por último.
D {# cópia ordenada dos índices ®1% # votos fracionários mod 1 (também conhecido como casas decimais) O # soma do acima (este é o número de assentos bônus) ò # arredondado para o mais próximo (necessário devido ao ponto flutuante bs) é # índice nas proporções ordenadas
Isso nos dá a (n + 1) th melhor relação, onde n é o número de assentos de bônus (+1 porque a indexação é baseada em 0). Assim, as partes que obtêm um assento de bônus são aquelas que têm uma proporção estritamente menor que isso.
fonte
Python 2 , 220 bytes
Experimente online!
Basicamente, apenas um golfe da implementação de referência ...
fonte
Geléia ,
6336 bytesExperimente online!
Um programa completo com três argumentos: o número de votos no formato descrito pela pergunta, bar e N nessa ordem. Retorna uma lista de listas de assentos. O rodapé no TIO é apenas para destacar a estrutura da lista da saída. (Caso contrário, Jelly esconde
[]
para listas de itens únicos.)Explicação
Submissão original (maior, porém mais eficiente)
Geléia , 63 bytes
Experimente online!
fonte
Wolfram - sem golfe
Estava curioso para resolvê-lo usando o LinearProgramming , não um candidato a golfe, mas talvez uma abordagem interessante para um problema:
Leia algumas explicações e experimente!
fonte