pengantar
Dalam pemilihan umum, orang ingin menghitung harga konstan per kursi parlemen. Ini berarti bahwa untuk N >= 0
kursi yang akan didistribusikan dan daftar ns
suara per partai, kami ingin menemukan nomor d
sedemikian rupa
sum(floor(n/d) for n in ns) == N
Untuk membuat hal-hal menarik (dan lebih mirip dunia nyata), kami menambahkan dua fakta lagi:
Dua partai dapat berkumpul dalam 'koalisi', sehingga kursi diberikan kepada 'koalisi' dengan jumlah suara untuk semua pihak di dalamnya. Kemudian kursi yang didapat 'koalisi' terbelah antara partai-partai dengan cara yang sama (temukan pembagi, dll.)
Partai yang tidak lulus persentase tertentu dari suara (mis. 3,25%) secara otomatis mendapat 0 kursi, dan suaranya tidak masuk dalam 'koalisi'.
Tantangan
Anda diberikan:
- Daftar daftar, masing-masing daftar bersarang berisi bilangan bulat (jumlah suara), dan panjangnya 1 untuk satu partai, atau panjang 2 untuk 'koalisi'.
- Persentase minimal suara (alias "bilah" untuk "rentetan") untuk mendapatkan kursi, sebagai fraksi (jadi 3,25% diberikan sebagai 0,0325)
- Total jumlah kursi yang akan didistribusikan antara semua pihak (integer)
Anda harus mencetak struktur daftar bersarang yang sama, dengan jumlah suara diganti dengan kursi parlemen.
Pemenang adalah kode dengan jumlah byte terkecil.
Kasus sudut:
- Mungkin ada (dan biasanya akan) lebih dari satu pembagi yang mungkin. Karena tidak ada dalam output, itu tidak masalah.
- Bayangkan
N=10
danns = [[1]]
, jadi pembagi mungkin 0,1 (bukan bilangan bulat) - Beberapa kasus tidak dapat diselesaikan, misalnya
ns=[[30],[30],[100]]
,bar=0
,N=20
. Ada batas did=7.5
mana jumlah nilai dasar melompat dari 19 hingga 21. Anda tidak diharapkan menyelesaikan kasus ini. (terima kasih kepada anggota komunitas Arnauld untuk menunjukkan kasus ini)
Contoh Input dan Output
Contoh Python3 yang sangat tidak dioptimalkan:
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))
Input contoh:
l = [[190970, 156473],
[138598, 173004],
[143666, 193442],
[1140370, 159468],
[258275, 249049],
[624, 819],
[1125881],
[152756],
[118031],
[74701]]
bar = 0.0325
N = 120
Dan hasilnya:
[[6, 4], [0, 5], [4, 6], [35, 5], [8, 8], [0, 0], [35], [4], [0], [0]]
Beberapa contoh lagi keluaran:
Jika bar=0.1
kami mendapat pertikaian yang menarik antara dua pihak karena tidak ada satu pun dari partai yang lebih kecil dihitung:
[[0, 0], [0, 0], [0, 0], [60, 0], [0, 0], [0, 0], [60], [0], [0], [0]]
Dan jika N=0
(kasus sudut) maka tentu saja tidak ada yang mendapat apa-apa:
[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0], [0], [0], [0]]
d=7.5
Anda mendapatkan lompatan dari 19 kursi menjadi 21 kursi.