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.Jawaban:
05AB1E ,
4239 byteCobalah online!
05AB1E tidak memiliki rekursi yang baik, jadi menerapkan pencarian biner seperti pada kode referensi akan menyakitkan. Untungnya, kita tidak perlu menemukan pembagi sama sekali!
Mari kita gunakan contoh sederhana: [600, 379, 12, 9] suara, 100 kursi, tidak ada koalisi, tidak ada bar. Pertama, kami menghitung berapa banyak kursi fraksional masing-masing pihak, mendefinisikan kursi fraksional sebagai
party_votes * seats / sum_of_votes
. Dalam contoh kami, itu menghasilkan [60, 37.9, 1.2, 0.9].Yang menarik adalah bahwa jika suatu pesta mendapat
f
kursi fraksional, itu akan mendapatkan kursi baikint(f)
atauint(f) + 1
nyata. Ini berarti kita sudah tahu bagaimana 60 + 37 + 1 = 98 kursi akan dialokasikan, dan kita dibiarkan dengan 2 "kursi bonus" untuk didistribusikan di antara 4 pihak (tidak ada pihak yang bisa mendapatkan lebih dari 1 kursi bonus). Kepada siapa kursi bonus ini pergi? Pihak-pihak dengan rasio tertinggif / (int(f) + 1)
(bukti dibiarkan sebagai latihan untuk pembaca). Dalam contoh kami, rasionya adalah[0.98, 0.997, 0.6, 0.9]
, jadi dua pihak pertama masing-masing mendapat kursi bonus.Mari kita lihat kodenya. Pertama, kami mengganti jumlah suara semua pihak yang tidak memenuhi bilah dengan 0:
Sekarang, untuk mengatasi kekurangan rekursi, kami menggunakan awkard
2F
untuk mengulangi kode utama dua kali. Pada pass pertama akan mendistribusikan total kursi antara koalisi, dan pada pass kedua akan mendistribusikan kursi masing-masing koalisi antara pihak-pihaknya. Karena operan pertama berjalan hanya sekali, tetapi operan kedua berjalan untuk setiap koalisi, ini melibatkan banyak pekerjaan yang sibuk.Oke, setelah bit yang tidak jelas ini, bagian atas tumpukan sekarang daftar suara (suara koalisi pada pass pertama, suara partai pada yang kedua), dan di bawah itu adalah jumlah kursi yang dialokasikan. Kami menggunakan ini untuk menghitung daftar kursi fraksional:
Sekarang, kami menghitung rasio:
Bitwise tidak berfungsi dengan baik, di sini. Ini memotong ke integer, menambahkan 1, dan meniadakan, semua dalam satu byte. Mengapa meniadakan? Di 05AB1E, pembagian dengan 0 menghasilkan 0, dan kami membutuhkan ini untuk mengurutkan terakhir.
D {# salinan disortir dari rasio ®1% # suara fraksional mod 1 (alias bagian desimal) O # jumlah di atas (ini adalah jumlah kursi bonus) ò # putaran ke terdekat (diperlukan karena titik mengambang bs) è indeks ke dalam rasio yang diurutkan
Ini memberi kita (n +1) rasio terbaik, di mana n adalah jumlah kursi bonus (+1 karena pengindeksan adalah berbasis 0). Dengan demikian, pihak-pihak yang mendapatkan kursi bonus adalah mereka yang memiliki rasio sangat kurang dari ini.
sumber
Python 2 , 220 byte
Cobalah online!
Pada dasarnya hanya golf dari implementasi referensi ...
sumber
Jelly ,
6336 byteCobalah online!
Program lengkap yang mengambil tiga argumen: jumlah suara dalam format yang dijelaskan oleh pertanyaan, bilah, dan N dalam urutan itu. Mengembalikan daftar daftar jumlah kursi. Footer pada TIO hanya untuk menyoroti struktur daftar output. (Kalau tidak, Jelly menyembunyikan
[]
daftar item tunggal.)Penjelasan
Pengajuan Asli (lebih besar tetapi lebih efisien)
Jelly , 63 byte
Cobalah online!
sumber
Wolfram - tidak ada golf
Hanya ingin tahu untuk menyelesaikannya menggunakan LinearProgramming , bukan kandidat golf, tapi mungkin pendekatan yang menarik untuk masalah:
Baca beberapa penjelasan dan cobalah!
sumber