introduction
Lors d'une élection générale, on souhaiterait calculer un prix constant par siège parlementaire. Cela signifie que pour la N >= 0
répartition des sièges et une liste ns
des votes par parti, nous aimerions trouver un nombre d
tel que
sum(floor(n/d) for n in ns) == N
Pour rendre les choses intéressantes (et plus comme le monde réel), nous ajoutons deux autres faits:
Deux partis peuvent se rassembler en une «coalition», de sorte que les sièges sont attribués à la «coalition» par la somme des voix de tous les partis. Ensuite, les sièges obtenus par la `` coalition '' sont répartis entre les partis de la même manière (trouver un diviseur, etc.)
Un parti qui n'a pas obtenu un certain pourcentage des voix (par exemple 3,25%) obtient automatiquement 0 siège, et ses votes ne comptent pas pour une «coalition».
Défi
On vous donne:
- Une liste de listes, chacune des listes imbriquées contient des nombres entiers (nombre de votes), et est de longueur 1 pour un parti unique, ou de longueur 2 pour une «coalition».
- Pourcentage minimal de votes (aka "bar" pour "barrage") pour obtenir des sièges, sous forme de fraction (donc 3,25% est donné comme 0,0325)
- Nombre total de sièges à répartir entre tous les partis (entier)
Vous devez imprimer la même structure de liste imbriquée, avec le nombre de votes substitué aux sièges du Parlement.
Winner est le code avec le plus petit nombre d'octets.
Cas d'angle:
- Il pourrait y avoir (et il y aura généralement) plus d'un diviseur possible. Comme il n'est pas dans la sortie, cela n'a pas vraiment d'importance.
- Imaginez
N=10
etns = [[1]]
, donc le diviseur peut être 0,1 (pas un entier) - Par exemple certains cas ne peuvent pas être résolus,
ns=[[30],[30],[100]]
,bar=0
,N=20
. Il y a une limite avecd=7.5
laquelle la somme des valeurs plancher passe de 19 à 21. On ne s'attend pas à ce que vous résolviez ces cas. (merci au membre de la communauté Arnauld d'avoir signalé ce cas)
Exemple d'entrée et de sortie
Un exemple Python3 très non optimisé:
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))
Exemple d'entrée:
l = [[190970, 156473],
[138598, 173004],
[143666, 193442],
[1140370, 159468],
[258275, 249049],
[624, 819],
[1125881],
[152756],
[118031],
[74701]]
bar = 0.0325
N = 120
Et sa sortie:
[[6, 4], [0, 5], [4, 6], [35, 5], [8, 8], [0, 0], [35], [4], [0], [0]]
Quelques autres exemples de sorties:
Si bar=0.1
nous obtenons une confrontation intéressante entre deux partis, car aucun des petits partis n'est compté dans:
[[0, 0], [0, 0], [0, 0], [60, 0], [0, 0], [0, 0], [60], [0], [0], [0]]
Et si N=0
(cas d'angle) alors bien sûr, personne ne reçoit rien:
[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0], [0], [0], [0]]
d=7.5
vous obtenez un saut de 19 sièges à 21 sièges.Réponses:
05AB1E ,
4239 octetsEssayez-le en ligne!
05AB1E manque de bonne récursivité, donc l'implémentation d'une recherche binaire comme dans le code de référence serait douloureuse. Heureusement, nous n'avons pas du tout besoin de trouver le diviseur!
Prenons un exemple simple: [600, 379, 12, 9] votes, 100 sièges, pas de coalitions, pas de bar. Premièrement, nous calculons le nombre de sièges fractionnaires que chaque parti obtient, en définissant les sièges fractionnaires comme
party_votes * seats / sum_of_votes
. Dans notre exemple, cela donne [60, 37,9, 1,2, 0,9].Ce qui est intéressant, c'est que si un parti obtient
f
des sièges fractionnaires, il obtiendra l'unint(f)
ou lesint(f) + 1
vrais sièges. Cela signifie que nous savons déjà comment 60 + 37 + 1 = 98 des sièges seront attribués, et il nous reste 2 "sièges bonus" à répartir entre les 4 partis (aucun parti ne peut obtenir plus d'un siège bonus). À qui s'adressent ces sièges bonus? Les parties avec le ratio le plus élevé def / (int(f) + 1)
(preuve laissée en exercice au lecteur). Dans nos exemples, les ratios sont[0.98, 0.997, 0.6, 0.9]
, donc les deux premiers partis obtiennent chacun un siège bonus.Jetons un coup d'œil au code. Tout d'abord, nous remplaçons le décompte des voix de tous les partis qui ne respectent pas la barre par 0:
Maintenant, pour contourner le manque de récursivité, nous utilisons un maladroit
2F
pour répéter le code principal deux fois. Lors de la première passe, il répartira le total des sièges entre les coalitions, et lors de la deuxième passe, il répartira les sièges de chaque coalition entre ses partis. Étant donné que la première passe ne s'exécute qu'une seule fois, mais que la deuxième passe s'exécute pour chaque coalition, cela implique un travail plutôt chargé.D'accord, après ce bit obscur, le haut de la pile est maintenant une liste de votes (votes de la coalition au premier passage, votes des partis au second), et en dessous, le nombre de sièges à attribuer. Nous l'utilisons pour calculer la liste des sièges fractionnaires:
Maintenant, nous calculons les ratios:
Bitwise ne fonctionne pas magnifiquement, ici. Il tronque en entier, ajoute 1 et nie, le tout dans un seul octet. Pourquoi nier? Dans 05AB1E, la division par 0 renvoie 0, et nous en avons besoin pour trier en dernier.
D {# copie triée des ratios ®1% # votes fractionnaires mod 1 (alias les parties décimales) O # somme de ce qui précède (c'est le nombre de sièges bonus) ò # arrondi au plus proche (requis en raison de la virgule flottante bs) è # index dans les ratios triés
Cela nous donne le (n + 1) e meilleur rapport, où n est le nombre de sièges bonus (+1 car l'indexation est basée sur 0). Ainsi, les partis qui obtiennent un siège bonus sont ceux qui ont un ratio strictement inférieur à celui-ci.
la source
Python 2 , 220 octets
Essayez-le en ligne!
Fondamentalement, juste un golf de la mise en œuvre de référence ...
la source
Gelée ,
6336 octetsEssayez-le en ligne!
Un programme complet prenant trois arguments: le nombre de votes dans le format décrit par la question, la barre et N dans cet ordre. Renvoie une liste de listes de nombre de sièges. Le pied de page sur TIO est juste pour mettre en évidence la structure de liste de la sortie. (Sinon, Jelly se cache
[]
pour les listes d'articles uniques.)Explication
Soumission originale (plus grande mais plus efficace)
Gelée , 63 octets
Essayez-le en ligne!
la source
Wolfram - pas de golf
Était simplement curieux de le résoudre en utilisant LinearProgramming , pas un candidat au golf, mais peut-être une approche intéressante à un problème:
Lisez quelques explications et essayez-les!
la source