국회 의사당 배포


13

소개

총선에서 의회 의석 당 일정한 가격을 계산하려고합니다. 즉, N >= 0좌석 배분 및 ns파티 당 투표 목록 을 위해 다음 d과 같은 숫자를 찾고 싶습니다.

sum(floor(n/d) for n in ns) == N 

일을 흥미롭게 만들고 현실 세계와 비슷하게 만들기 위해 두 가지 사실을 더 추가합니다.

  1. 두 당사자가 '연합'에 모일 수 있으므로 모든 당사자에 대한 투표의 합에 의해 좌석이 '연합'에 제공됩니다. 그런 다음 '연합'이 얻은 좌석은 비슷한 방식으로 당사자간에 나뉩니다 (찾기 제수 등).

  2. 특정 비율의 투표를 통과하지 못한 당사자 (예 : 3.25 %)는 자동으로 0 석을 얻으며 해당 투표는 '연합'에 포함되지 않습니다.

도전

당신은 주어진다 :

  1. 목록의 목록, 각 중첩 목록에는 정수 (투표 수)가 포함되며 단일 당사자의 경우 길이가 1이고 '연합'의 경우 길이가 2입니다.
  2. 자리를 얻는 최소 투표율 (일명 "막대기"는 "bar") (분수) (3.25 %는 0.0325로 표시)
  3. 모든 당사자 (정수) 사이에 분배 될 총 좌석 수

국회 의석으로 대체 된 투표 수를 사용하여 동일한 중첩 목록 구조를 인쇄해야합니다.

우승자는 가장 적은 양의 바이트를 가진 코드입니다.

코너 케이스 :

  • 둘 이상의 가능한 제수가있을 수 있습니다 (보통있을 것입니다). 출력에 없기 때문에 실제로 중요하지 않습니다.
  • 상상 N=10ns = [[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]]

5
PPCG에 오신 것을 환영합니다!
Arnauld 2018 년

CGCC (이전의 PPCG)에 오신 것을 환영합니다! 필자는 Python 강조 표시를 추가하여 코드를 더 읽기 쉽게 만들었으며 입력 아래에 코드를 입력하여 입력 출력을 더 가깝게 만들었습니다. 또한 두 개의 관련 태그를 추가했습니다. 그래도 좋은 첫 번째 도전, 그래서 +1! 추신 : 도전 과제샌드 박스를 사용하여 도전 과제 를 주에 게시하기 전에 도전 과제 에 대한 피드백을 얻을 수 있습니다. 이 경우에는 도전 과제가 분명하다고 생각합니다. 테스트 케이스를 몇 개 더 추가 할 수 있습니까? 숙박 : 즐기
케빈 Cruijssen

물론 @KevinCruijssen은 두 가지 사례를 더 추가했습니다. 기존의 산출물에 관해서는 그것이 최근 선거의 정확한 결과이기 때문에 그것이 사실이라고 믿습니다 :)
scf

@Arnauld 호기심으로 인해 해당 테스트 케이스에 대해 예상되는 결과는 무엇입니까?
Kevin Cruijssen '

1
나는 이미 코너 케이스에 총알을 추가했습니다. 경계 d=7.5에서 19 석에서 21 석으로 점프 할 때 이것이 해결할 수없는 사건이라고 생각합니다 .
scf 2016 년

답변:


2

05AB1E , 42 39 바이트

ÐOOI*@*DO¸I¸¸2Fнζε`sDO/*Щ±/D{®1%Oòè‹+ï

온라인으로 사용해보십시오!

05AB1E에는 재귀가 충분하지 않으므로 참조 코드에서와 같이 이진 검색을 구현하는 데 어려움이 있습니다. 고맙게도, 우리는 제수를 전혀 찾을 필요가 없습니다!

[600, 379, 12, 9] 투표, 100 석, 연립 금지, 바 없음 등 간단한 예를 살펴 보겠습니다. 먼저 각 당사자가 얻는 소수 자리수를 계산하여 소수 자리수를로 정의 party_votes * seats / sum_of_votes합니다. 이 예에서는 [60, 37.9, 1.2, 0.9]가 생성됩니다.

재미있는 점은 파티가 f분수 좌석을 얻는 경우 int(f)또는 int(f) + 1실제 좌석을 얻는다는 것 입니다. 이것은 우리가 60 + 37 + 1 = 98 석의 좌석이 배정되는 방법을 이미 알고 있다는 것을 의미하며, 우리는 4 명에게 분배하기 위해 2 개의“보너스 좌석”이 남아 있습니다 (파티는 보너스 좌석을 1 명 이상 가질 수 없습니다). 이 보너스 좌석은 누구에게 가나 요? 비율이 가장 높은 당사자 f / (int(f) + 1)(독자에게 연습으로 남은 증거). 이 예에서 비율은입니다 [0.98, 0.997, 0.6, 0.9]. 따라서 첫 두 당사자는 각각 보너스 좌석을 얻습니다.


코드를 보자. 먼저,이 기준을 충족하지 못한 모든 당사자의 투표 수를 0으로 바꿉니다.

Ð          # triplicate the first input (list of votes)
 OO        # flattened sum
   I*      # multiply by the second input (bar)
     @     # greater than? (returns 0 or 1)
      *    # multiply

이제 재귀 부족을 해결하기 위해 어 커드 2F를 사용 하여 기본 코드를 두 번 반복합니다. 첫 번째 패스에서는 연합 사이에 총 좌석 수를 분배하고 두 번째 패스에서는 각 연합의 좌석 수를 당사자간에 분배합니다. 첫 번째 패스는 한 번만 실행되지만 두 번째 패스는 각 연합에 대해 실행되므로 많은 작업이 필요합니다.

DO¸I¸¸2Fнζε`s    # i don’t want to detail this tbh

자,이 모호한 비트 이후, 스택의 맨 위에는 이제 투표 목록 (첫 번째 패스의 연합 투표, 두 번째 파티의 투표)이 있고 그 아래에 할당 할 좌석 수가 있습니다. 이것을 사용하여 소수 자리 목록을 계산합니다.

D        # duplicate
 O       # sum  
  /      # divide each vote count by the sum
   *     # multiply by the number of seats
    ©    # save the fractional seats in variable r

이제 비율을 계산합니다.

Ð            # triplicate
 ±           # bitwise not
  /          # divide

비트 단위는 아름답게 작동하지 않습니다. 정수로 자르고 1을 더한 다음 모두 1 바이트로 무효화합니다. 왜 부정합니까? 05AB1E에서 0으로 나누면 0이 반환되고 마지막으로 정렬하려면 이러한 값이 필요합니다.

D {# 비율의 정렬 된 사본 ®1 % # 분수 표 mod 1 (일부 소수 부분) O # 위의 합계 (보너스 시트 수) ò # 가장 가까운 반올림 (부동 소수점 b로 인해 필요) è # 정렬 된 비율로 색인

이것은 우리에게 (n + 1) 번째 최고 비율을 제공합니다. 여기서 n은 보너스 좌석 수입니다 (인덱싱이 0을 기반으로하기 때문에 +1). 따라서 보너스 좌석을 얻는 당사자는 이보다 엄격하게 비율이 낮은 당사자입니다.

‹      # less than
 +     # add to the fractional seats
  ï    # truncate to integer

아주 좋아요 수학을 사용하여 코드를 최적화하는 좋은 방법 :)
scf

3

파이썬 2 , 220 바이트

def d(l,n,a=0,b=1.):s=sum(x//b for x in l);return s-n and d(l,n,*[a,b,(a+b)/2,b*2][s>n::2])or b
def f(l,b,n):l=[[x*(x>=b*sum(sum(l,[])))for x in r]for r in l];return[[v//d(x,sum(x)//d(map(sum,l),n))for v in x]for x in l]

온라인으로 사용해보십시오!

기본적으로 참조 구현의 골프 ...


1

젤리 , 63 36 바이트

F×S<ḷ×ḷµ§⁵:,1_×¥:@"§IṠʋ÷9ɗ¥ƬṪṪƲ¥¥@⁺"

온라인으로 사용해보십시오!

질문에 의해 설명 된 형식의 투표 수, 막대 및 N 순서로 세 개의 인수를 취하는 전체 프로그램. 좌석 수 목록을 반환합니다. TIO의 바닥 글은 출력의 목록 구조를 강조 표시하는 것입니다. 그렇지 않으면 젤리가 []단일 항목 목록을 숨 깁니다 .

설명

F×S<ḷ×ḷµ§⁵:,1_×¥:@"§IṠʋ÷9ɗ¥ƬṪṪƲ¥¥@⁺"

F                                   | Flatten vote counts
 ×                                  | Multiply by bar
  S                                 | Sum
   <ḷ                               | Less than original vote counts (vectorises and respects input list structure)
     ×ḷ                             | Multiply by original vote counts
       µ                            | Start a new monadic link with processed vote counts as input
        §                           | Vectorised sum

         ⁵                      ¥@  | Apply the following as a dyad with the number of seats as the right argument and the vectorised sum of votes as left

           ,                  Ʋ¥    |(*)- Pair vote counts with seat sum and find divisor using the following as a monad:
            1             ¥Ƭ        |     - Starting with 1 as a guess for divisor, and using the paired vote counts and seat sum as the right argument, apply the following as a dyad, collecting intermediate results, until the results repeat
                         ɗ          |       - Following as a dyad:
                      ʋ             |         - Following as a dyad:
                :@"                 |           - Integer divide with arguments zipped and reversed, i.e. divide cote counts by current divisor guess and leave total seats alone
                   §                |           -  Vectorised sum (will sum vote counts but leave seat number alone)
                    I               |           - Find differences i.e. desired total seats minus current calculation based on current divisor guess. Will return a list.
                     Ṡ              |           - Sign of this (-1, 0 or 1)
                       ÷9           |         - Divide by 9 (-0.111, 0 or 0.111)
             _×¥                    |     - Now multiply the current divisor guess by this and subtract it from that guess to generate the next guess. If the current guess is correct, the guess will be unchanged and so the Ƭ loop will terminate
                            ṪṪ      |     - Take the last item twice (first time to get the final
                               output of the Ƭ loop and second to remove the list introduced by I
         :                          | - Integer divide the vote counts by the output of the above

                                  ⁺"| Apply the above dyad from the step labelled (*) again, this time with the output of the previous step (total votes per coalition) as right argument and the vote counts as left argument, zipping the two together and running the link once for each pair

원본 제출 (크지 만 효율적)

젤리 , 63 바이트

:S_3ƭƒṠ©ḢḤ;$;ṪƲṖÆm;ḊƲ®‘¤?ߥ/}ṛ¹?,
1,0;çḢḢ
FS×Ċ’<ḷ×ḷµ:"§:⁵ç$$ç"Ɗ

온라인으로 사용해보십시오!


좋은 제출. 입력 [[1]] 0.0 10으로 시도했는데 [[10]]을 반환 할 것으로 예상됩니다 (코너의 경우 글 머리 기호 2 참조). 버그가 아닌 매우 긴 런타임임을 확인할 수 있습니까?
scf 2016 년

원래 제출은 해당 입력 BTW와 함께 작동합니다.
scf 2016 년

@scf 나는 투표가 항상 좌석보다 훨씬 높다고 잘못 생각했다. 수정 된 버전은 제대로 작동해야하며 훨씬 더 효율적입니다.
Nick Kennedy

1
좋아, 좋아 보인다! 코드를 조금 설명 할 수 있다면 좋을 것입니다.
scf

순진한 질문 : 왜 천장이 중요한가? 내가 올바르게 이해하면 최소한의 투표로 한도를 정하지 만 비교할 필요는 없습니다.
scf

1

볼프람-골프 없음

골프 후보자가 아닌 LinearProgramming 을 사용하여 문제를 해결 하는 데 관심이 있었지만 문제에 대한 흥미로운 접근법 일 수 있습니다.

findDivisor[l_, n_] := Quiet@Module[{s, c, r, m, b, cons, sol},
   s = Length[l];
   c = Append[ConstantArray[0, s], 1];
   r = Thread[Append[IdentityMatrix[s], -l]];
   m = Append[Join[r, r], Append[ConstantArray[1, s], 0]];
   b = Append[Join[ConstantArray[{0, -1}, s], ConstantArray[{-1, 1}, s]], {n, 0}];
   cons = Append[ConstantArray[Integers, s], Reals];
   sol = LinearProgramming[c, m, b, 0, cons];
   {1/sol[[-1]], Most@sol}
   ]
solve[l_, bar_, n_] := 
 With[{t = l /. x_ /; x <= bar Total[l, 2] -> 0},
  With[{sol = findDivisor[Total /@ t, n]}, 
   {First@sol, MapThread[findDivisor, {t, Last@sol}]}]
  ]

몇 가지 설명을 읽고 사용해보십시오!


경쟁 업체는 아니지만 방법과 코드에 대한 설명이 있으면 교육 목적에 적합합니다.
scf 2016 년

@scf 나는 그것을 설명하려는 나의 시도에 대한 링크를 추가했다
swish
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.