บทนำ
ในการเลือกตั้งทั่วไปเราต้องการคำนวณราคาคงที่ต่อที่นั่งของรัฐสภา ซึ่งหมายความว่าสำหรับN >= 0
ที่นั่งที่จะแจกจ่ายและรายชื่อns
คะแนนต่อปาร์ตี้เราต้องการค้นหาหมายเลขd
ดังกล่าว
sum(floor(n/d) for n in ns) == N
เพื่อให้สิ่งต่าง ๆ น่าสนใจ (และเหมือนโลกแห่งความเป็นจริง) เราได้เพิ่มข้อเท็จจริงสองประการ:
ทั้งสองฝ่ายสามารถรวมตัวกันเป็น 'พันธมิตร' เพื่อให้ที่นั่งได้รับ 'พันธมิตร' ด้วยคะแนนรวมสำหรับทุกฝ่ายในนั้น จากนั้นที่นั่งที่ 'พันธมิตร' ได้รับจะถูกแยกออกระหว่างฝ่ายในแบบเดียวกัน (ค้นหาตัวหาร ฯลฯ )
ปาร์ตี้ที่ไม่ผ่านการลงคะแนนเสียงในระดับที่แน่นอน (เช่น 3.25%) จะได้รับ 0 ที่นั่งโดยอัตโนมัติและการโหวตจะไม่นับสำหรับ 'การรวม'
ท้าทาย
คุณจะได้รับ:
- รายการของรายการแต่ละรายการซ้อนกันประกอบด้วยจำนวนเต็ม (จำนวนโหวต) และมีความยาว 1 สำหรับงานปาร์ตี้เดี่ยวหรือยาว 2 สำหรับ 'พันธมิตร'
- เปอร์เซ็นต์การโหวตน้อยที่สุด (aka "บาร์" สำหรับ "เขื่อนกั้นน้ำ") เพื่อรับที่นั่งเป็นเศษส่วน (ดังนั้น 3.25% จะได้รับเป็น 0.0325)
- จำนวนที่นั่งทั้งหมดที่จะแจกจ่ายระหว่างทุกฝ่าย (จำนวนเต็ม)
คุณจะต้องพิมพ์โครงสร้างรายการซ้อนเดียวกันด้วยจำนวนคะแนนที่แทนที่ด้วยที่นั่งของรัฐสภา
ผู้ชนะคือรหัสที่มีจำนวนไบต์น้อยที่สุด
กรณีมุม:
- อาจมี (และโดยปกติจะ) มากกว่าหนึ่งตัวหารที่เป็นไปได้ เนื่องจากมันไม่ได้อยู่ในเอาต์พุตมันจึงไม่สำคัญ
- ลองนึกภาพ
N=10
และns = [[1]]
ดังนั้นตัวหารอาจเป็น 0.1 (ไม่ใช่จำนวนเต็ม) - บางกรณีไม่สามารถแก้ไขได้เช่น
ns=[[30],[30],[100]]
, ,bar=0
N=20
มีขอบเขตd=7.5
ที่การรวมค่าของการปูพื้นกระโดดจาก 19 ถึง 21 คุณไม่คาดว่าจะแก้ปัญหากรณีเหล่านี้ (ขอบคุณสมาชิกชุมชน Arnauld ที่ชี้กรณีนี้ออกมา)
ตัวอย่างอินพุตและเอาต์พุต
ตัวอย่าง 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))
อินพุตตัวอย่าง:
l = [[190970, 156473],
[138598, 173004],
[143666, 193442],
[1140370, 159468],
[258275, 249049],
[624, 819],
[1125881],
[152756],
[118031],
[74701]]
bar = 0.0325
N = 120
และเอาท์พุท:
[[6, 4], [0, 5], [4, 6], [35, 5], [8, 8], [0, 0], [35], [4], [0], [0]]
ตัวอย่างผลลัพธ์เพิ่มเติม:
หากbar=0.1
เราได้รับความสนใจจากทั้งสองฝ่ายเนื่องจากไม่มีฝ่ายใดที่มีขนาดเล็กกว่าเข้าร่วม:
[[0, 0], [0, 0], [0, 0], [60, 0], [0, 0], [0, 0], [60], [0], [0], [0]]
และถ้าN=0
(กรณีมุม) แน่นอนว่าไม่มีใครได้รับอะไร:
[[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0], [0], [0], [0]]
d=7.5
คุณกระโดดจาก 19 ที่นั่งเป็น 21 ที่นั่ง