Wprowadzenie
W wyborach powszechnych chcielibyśmy obliczyć stałą cenę za mandat parlamentu. Oznacza to, że w N >= 0
celu rozdzielenia miejsc i listy ns
głosów na partię chcielibyśmy znaleźć taką liczbę d
, która
sum(floor(n/d) for n in ns) == N
Aby uczynić rzeczy interesującymi (i bardziej podobnymi do realnego świata), dodajemy dwa dodatkowe fakty:
Dwie partie mogą zebrać się w „koalicji”, dzięki czemu mandaty zostaną przyznane „koalicji” przez sumę głosów wszystkich partii w niej uczestniczących. Następnie mandaty „koalicji” są podzielone między partiami w podobny sposób (znajdź dzielnik itp.)
Partia, która nie uzyskała określonego odsetka głosów (np. 3,25%) automatycznie otrzymuje 0 mandatów, a jej głosy nie liczą się do „koalicji”.
Wyzwanie
Dostaniesz :
- Lista list, każda z list zagnieżdżonych zawiera liczby całkowite (liczba głosów) i ma długość 1 dla jednej partii lub długość 2 dla „koalicji”.
- Minimalny procent głosów (aka „bar” dla „zapory”), aby uzyskać miejsca, jako ułamek (więc 3,25% podano jako 0,0325)
- Całkowita liczba miejsc do podziału między wszystkie strony (liczba całkowita)
Masz wydrukować tę samą strukturę listy zagnieżdżonej, z liczbą głosów zastąpionych miejscami w parlamencie.
Zwycięzca to kod z najmniejszą ilością bajtów.
Narożniki:
- Może istnieć (i zwykle będzie) więcej niż jeden możliwy dzielnik. Ponieważ nie ma go na wyjściu, tak naprawdę nie ma znaczenia.
- Wyobrazić sobie,
N=10
ins = [[1]]
, dlatego mogą być dzielnikiem 0,1 (nie całkowitą) - Niektóre przypadki nie można rozwiązać, na przykład
ns=[[30],[30],[100]]
,bar=0
,N=20
. Istnieje granica, wd=7.5
której suma wartości zmiennoprzecinkowych skacze z 19 do 21. Nie oczekuje się, że rozwiążesz te przypadki. (podziękowania dla członka społeczności Arnaulda za wskazanie tej sprawy)
Przykład wejścia i wyjścia
Bardzo niezoptymalizowany przykład 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))
Przykładowe dane wejściowe:
l = [[190970, 156473],
[138598, 173004],
[143666, 193442],
[1140370, 159468],
[258275, 249049],
[624, 819],
[1125881],
[152756],
[118031],
[74701]]
bar = 0.0325
N = 120
I jego wydajność:
[[6, 4], [0, 5], [4, 6], [35, 5], [8, 8], [0, 0], [35], [4], [0], [0]]
Kilka innych przykładowych wyników:
Jeśli bar=0.1
uzyskamy interesujący spór między dwiema stronami, ponieważ żadna z mniejszych partii nie jest liczona:
[[0, 0], [0, 0], [0, 0], [60, 0], [0, 0], [0, 0], [60], [0], [0], [0]]
A jeśli N=0
(przypadek narożny) to oczywiście nikt nic nie dostaje:
[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0], [0], [0], [0]]
d=7.5
masz skok z 19 miejsc do 21 miejsc.Odpowiedzi:
05AB1E ,
4239 bajtówWypróbuj online!
05AB1E nie ma dobrej rekurencji, więc wdrożenie wyszukiwania binarnego jak w kodzie referencyjnym byłoby bolesne. Na szczęście wcale nie musimy znajdować dzielnika!
Posłużmy się prostym przykładem: [600, 379, 12, 9] głosów, 100 mandatów, brak koalicji, brak baru. Najpierw obliczamy, ile miejsc ułamkowych otrzymuje każda strona, definiując jako ułamkowe miejsca
party_votes * seats / sum_of_votes
. W naszym przykładzie daje to [60, 37,9, 1,2, 0,9].Interesujące jest to, że jeśli impreza otrzyma
f
ułamkowe miejsca, dostanie jednoint(f)
lub więcejint(f) + 1
miejsc. Oznacza to, że wiemy już, w jaki sposób zostanie przydzielonych 60 + 37 + 1 = 98 miejsc, i mamy 2 „miejsca premiowe” do rozdzielenia między 4 strony (żadna ze stron nie może uzyskać więcej niż 1 miejsce premiowe). Do kogo trafiają te dodatkowe miejsca? Strony z najwyższym współczynnikiemf / (int(f) + 1)
(dowód pozostawiony jako ćwiczenie dla czytelnika). W naszych przykładach współczynniki są[0.98, 0.997, 0.6, 0.9]
, więc każda z pierwszych dwóch grup otrzyma dodatkowe miejsce.Rzućmy okiem na kod. Po pierwsze, zastępujemy liczbę głosów wszystkich stron, które nie spełniły kryteriów, liczbą 0:
Teraz, aby obejść brak rekurencji, używamy dziwnego,
2F
aby dwukrotnie powtórzyć główny kod. Przy pierwszym przejściu rozdzieli całkowitą liczbę miejsc między koalicjami, a przy drugim przejściu rozdzieli miejsca każdej koalicji między partiami. Ponieważ pierwsze przejście przebiega tylko raz, ale drugie przejście przebiega dla każdej koalicji, wymaga to raczej dużo pracy.Ok, po tym niejasnym bicie, na szczycie stosu znajduje się teraz lista głosów (głosy koalicyjne przy pierwszym podaniu, głosy partyjne przy drugim), a poniżej to liczba miejsc do przydzielenia. Używamy tego do obliczenia listy miejsc ułamkowych:
Teraz obliczamy współczynniki:
Bitowe nie działa pięknie tutaj. Obcina się do liczby całkowitej, dodaje 1 i neguje, wszystko w jednym bajcie. Dlaczego negować? W 05AB1E dzielenie przez 0 zwraca 0 i musimy je posortować na końcu.
D {# posortowana kopia współczynników ® 1% # głosów ułamkowych mod 1 (aka części dziesiętne) O # suma powyższych (jest to liczba miejsc premiowych) ò # zaokrąglenie do najbliższego (wymagane ze względu na zmiennoprzecinkową bs) è # indeks do posortowanych proporcji
To daje nam (n + 1) najlepszy stosunek, gdzie n jest liczbą miejsc premiowych (+1, ponieważ indeksowanie opiera się na 0). Tak więc stronami, które dostają miejsce premiowe, są te, których stosunek jest ściśle mniejszy niż ten.
źródło
Python 2 , 220 bajtów
Wypróbuj online!
Zasadniczo tylko golf implementacji referencyjnej ...
źródło
Galaretka ,
6336 bajtówWypróbuj online!
Pełny program przyjmujący trzy argumenty: liczbę głosów w formacie opisanym przez pytanie, słupek i N w tej kolejności. Zwraca listę list liczby miejsc. Stopka w TIO służy jedynie do podświetlenia struktury listy wyników. (W przeciwnym razie galaretki chowają się
[]
na listach z jednym przedmiotem).Wyjaśnienie
Oryginalne zgłoszenie (większe, ale bardziej wydajne)
Galaretka , 63 bajty
Wypróbuj online!
źródło
Wolfram - bez golfa
Byłem ciekawy rozwiązania go za pomocą LinearProgramming , a nie kandydata do gry w golfa, ale może interesujące podejście do problemu:
Przeczytaj wyjaśnienie i wypróbuj je!
źródło