Comment detail

議席数をドント方式で (Nested Flatten)

This comment is reply for 1258 JDO: Prolog です。とーても、長いコード...(議席数をドント方式で). Go to thread root.

こんな感じでも書けますよ。
predsortがremove duplicateなのでちょっと残念ですが。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
votes_sort(L,R) :- predsort(votes_compare, L, R).

votes_compare(K,(_,A,Ca),(_,B,Cb)) :-Va is float(A) / Ca, Vb is float(B) / Cb, compare(K0,Vb,Va),(K0=='='->compare(K,Ca,Cb);K0=K).

dhondt(0,_,R,R).
dhondt(I,L,H,R):-votes_sort(L,[(N,V,C)|Ls]),succ(I1,I),succ(C,C1),count(N,H,Hs),dhondt(I1, [(N,V,C1)|Ls],Hs,R).

count(X,[(X,N)|Hs],[(X,N1)|Hs]):-succ(N,N1).
count(X,[H|Hs],[H|Rs]) :- count(X,Hs,Rs).
count(X,[],[(X,1)]).

:-dhondt(100, [(a,123,1), (b,4,1), (c,56,1), (d,78,1)], [], R), writeln(R).
まぁ。なんと短い。predsort なんていう便利な述語があるんですねぇ。これに、述語 count でハッシュテーブルですね。なにより、d'Hondt方式のアルゴリズムとして、無駄のない計算になってますよね。私のように、無駄なリストだらだら生成したりしない。。。私のような Prolog ズブの初心者からすると、とても、勉強になるコードでした。ありがとうございました。
Java です。katsu さんの Prolog プログラムを Java で焼き直ししてみました。(なんだか見た目、長いですね。。。)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import java.lang.Comparable ;
import java.util.Arrays ;

class dHondtMethod
  {
  static class Vote implements Comparable
    {
    String 政党名 ; int 得票数 ; int 既得の議席数 ;
    Vote (String , int , int )
      {政党名 =  ; 得票数 =  ; 既得の議席数 =  ;} 

    public int compareTo (Object another_)
      {
      Vote another = (Vote) another_ ;

      Double thisValue
        = new Double (this.得票数 / (this.既得の議席数 + 1.)) ;
      Double anotherValue
        = new Double (another.得票数 / (another.既得の議席数 + 1.)) ;

      int cmp = thisValue .compareTo (anotherValue) ;
      return cmp!=0 ? cmp : this.得票数 - another.得票数 ;
      }

    public String toString ()
      {return "(政党名="+政党名+", 得票数="+得票数
              +", 既得の議席数="+既得の議席数+")" ;}
    }

  public static void main (String [] _)
    {
    int 定数 = 100 ;

    Vote [] votes = 
      {new Vote ("A党", 123, 0), new Vote ("B党",   4, 0),
       new Vote ("C党",  56, 0), new Vote ("D党",  78, 0)} ;

    while (0< 定数)
      {
      Arrays.sort (votes) ;
      Vote last = votes [votes.length - 1] ; // 最大のもの
      ++last.既得の議席数 ;
      --定数 ;
      }

    for (int i=0; i<votes.length; ++i)
      {System.out .println (votes [i]) ;}
    }
  }
Scheme です。 Java で書いてみて分かったのですが、議席数の計算のつど、[A,B,C,D] 全体で sort する必要はないですよね。全体で sort が必要なのは最初の1回だけで、次回以降は、その時 議席を獲得した党の順位が入れ替わるだけ。たとえば、議席計算の最初の第1回目では全体で sort すると A党(=123), D党(=78), C党(=56), B党(=4) の順になり A党 が議席獲得ですが、次回は、A党の数値のみが変わる(123→66.5)だけなので、A党の順位のみを気にすればいいだけ。こう考えると、マージソートにすれば、最適化を図れるわけですよね。つまり、残りの [D, C, B] に対して、大きい順で マージ (追加) する処理をすれば、最小限の sort 処理になります。実際、今の例ですと、D党(=78) と入れ替わるだけで、すみます。。。。ということで、長くなりましたが、マージ方式のアルゴリズムで書いてみました。時々は、気分を変えて、Scheme で書いてみました。(Scheme らしからぬ書き方ですが。。。)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
; Vote オブジェクトの定義

(define (new_Vote party-name vote-count seat-count)
  (list party-name vote-count seat-count))
(define (Vote_getPartyName this) (car this))
(define (Vote_getVoteCount this) (cadr this))
(define (Vote_getSeatCount this) (caddr this))

(define (Vote_increaseSeatCount this)
  (new_Vote
    (Vote_getPartyName this)
    (Vote_getVoteCount this)
    (+ (Vote_getSeatCount this) 1)
  )
)

(define (Vote_isLessThan this another)
  (let
    (
    (thisValue (/ (Vote_getVoteCount this) (+ (Vote_getSeatCount this) 1)))
    (anotherValue (/ (Vote_getVoteCount another) (+ (Vote_getSeatCount another)1)))
    )

    (if (= thisValue anotherValue)
      (< (Vote_getVoteCount this) (Vote_getVoteCount another))
      (< thisValue anotherValue)
    )
  )
)

(define (Vote_display this)
  (display "party-name: ") (display (Vote_getPartyName this)) (display ", ")
  (display "vote-count: ") (display (Vote_getVoteCount this)) (display ", ")
  (display "seat-count: ") (display (Vote_getSeatCount this)) (newline)
)

; d'Hondt 方式の要

  ; 新しい Vote オブジェクトを大きい順で追加する

  (define (dHondt_add this vote)
    (if (null? this)
      (list vote)
    (if (Vote_isLessThan (car this) vote)
      (cons vote this)
      (cons (car this) (VoteList_add (cdr this) vote)) ; .... ?
    ))
  )


; ここが d'Hondt の処理

(define (dHondt total-seat-count sorted-vote-list)
  (do () ((= 0 total-seat-count))
    ; 次回の 今回議席を獲得した党 (car) の議席数を
    ; 1増やして (increaseSeatCount)、
    ; 残りの党たちのリスト (cdr) に add する
    ; (このアルゴリズムのポイント)
    (set! sorted-vote-list
      (dHondt_add
        (cdr sorted-vote-list)
        (Vote_increaseSeatCount (car sorted-vote-list))
      )
    )
    (set! total-seat-count (- total-seat-count 1))
  )
  sorted-vote-list
)

; お試しコード ------------------------------------------------------------

(define otameshi-list ())
(set! otameshi-list (dHondt_add otameshi-list (new_Vote "A" 123 0)))
(set! otameshi-list (dHondt_add otameshi-list (new_Vote "B"   4 0)))
(set! otameshi-list (dHondt_add otameshi-list (new_Vote "C"  56 0)))
(set! otameshi-list (dHondt_add otameshi-list (new_Vote "D"  78 0)))

(set! otameshi-list (dHondt 100 otameshi-list))

(Vote_display (car otameshi-list))
(Vote_display (cadr otameshi-list))
(Vote_display (caddr otameshi-list))
(Vote_display (cadddr otameshi-list))
おっとっと。46行目、書き間違いです。(Upの直前に名前変更したもので、、、)すみません。
1
2
3
: (cons (car this) (VoteList_add (cdr this) vote))

: (cons (car this) (dHondt_add (cdr this) vote))

Index

Feed

Other

Link

Pathtraq

loading...