石頭からの疑問

 投稿者:GAI  投稿日:2010年 2月10日(水)17時06分8秒
  自然数nの分割方法で
5=1+1+1+1+1
 =1+1+1+2
 =1+1+3
 =1+2+2
 =1+4
 =2+3
 =5
と7通りの方法が存在する。

一般に自然数nの分割方法をp(n)とするとき
nをk個に分割する方法をp(k,n)で表せば

p(n)=Σk=1~n p(k,n)


p(1,n)=p(n,n)=1
p(k,n)=p(k-1,n-1)+p(k,n-k)

なる漸化式もどきが成立するが(2番目の式がなにかがよく掴めないが・・・)
p(n)の一般式を表す式は存在しないと書かれていた。
また一方で

n:p(n)
0 1
1 1
2 2
3 3
4 5
5 7
6 11
7 15
8 22
9 30
10 42
11 56
12 77
13 101
14 135
15 176
16 231
17 297
18 385
19 490
20 627
21 792
22 1002
23 1255
24 1575
25 1958
26 2436
27 3010
28 3718
29 4565
30 5604
31 6842
32 8349
33 10143
34 12310
35 14883
36 17977
37 21637
38 26015
39 31185
40 37338
41 44583
42 53174
43 63261
44 75175
45 89134
46 105558
47 124754
48 147273
49 173525
50 204226
51 239943
52 281589
53 329931
54 386155
55 451276
56 526823
57 614154
58 715220
59 831820
60 966467
61 1121505
62 1300156
63 1505499
64 1741630
65 2012558
66 2323520
67 2679689
68 3087735
69 3554345
70 4087968
71 4697205
72 5392783
73 6185689
74 7089500
75 8118264
76 9289091
77 10619863
78 12132164
79 13848650
80 15796476
81 18004327
82 20506255
83 23338469
84 26543660
85 30167357
86 34262962
87 38887673
88 44108109
89 49995925
90 56634173
91 64112359
92 72533807
93 82010177
94 92669720
95 104651419
96 118114304
97 133230930
98 150198136
99 169229875
100 190569292
・・・・・・・・
(以下すごい数まで調べられている。)
なる表も存在している。
じゃーこれは一体どのようにして計算されたものであるのか?
という疑問が湧いてくる。

ネットで調べるとオイラーの五角数定理だの母関数だのと解説されているが、私一人では解読に至りません。
もしこれに精通された方がおられましたら、プログラムはどう組み、どんな手順でこんな手作業では不可能なところまでの値が求められていくのか解説をお願いします。
 

Re: 石頭からの疑問

 投稿者:山中和義  投稿日:2010年 2月10日(水)19時48分20秒
  > No.1020[元記事へ]

GAIさんへのお返事です。

> じゃーこれは一体どのようにして計算されたものであるのか?

漸化式をそのまま記述すれば
!分割数(partition number)

FUNCTION p(n,k)
   IF k=1 OR k=n THEN !p(n,1)=p(n,n)=1
      LET p=1
   ELSEIF n<k THEN !p(n,k)=p(n-k,k)+p(n-1,k-1)
      LET p=0
   ELSE
      LET p=p(n-k,k)+p(n-1,k-1)
   END IF
END FUNCTION

FOR i=1 TO 30 !1~30まで

   LET pn=0
   FOR k=1 TO i !p(n)=Σ[k=1,n]p(n,k)
      LET pn=pn+p(i,k)
   NEXT k
   PRINT i; pn

NEXT i

END

組合せ(comb(n,r))やフィボナッチ数列なども再帰関数で計算できます。
ただ、毎回最初に戻って値を確定するので、nが多くなると負荷がかかります。
(遅くなるし、システム領域がなくなる(スタックオーバーフローが発生する)


表計算のように結果を残しながら、nを1から順に求めるのがいいでしょう。
(計算は速いが、メモリは浪費する)

参考 パスカルの三角形
!分割数(partition number)

LET N=30

DIM p(N,N) !左下充填の行列をつくる
MAT p=ZER !n<kならp(n,k)=0
FOR i=1 TO N
   LET p(i,1)=1 !p(n,1)=1
   LET p(i,i)=1 !p(n,n)=1
NEXT i
FOR i=1 TO N !左上から順に計算していく
   FOR k=2 TO i-1
      LET p(i,k)=p(i-k,k)+p(i-1,k-1) ! !p(n,k)=p(n-k,k)+p(n-1,k-1)
   NEXT k
NEXT i
MAT PRINT USING(REPEAT$(" ####",N)): p !debug

FOR i=1 TO N !1~Nまで

   LET pn=0 !p(n)=Σ[k=1,n]p(n,k)
   FOR k=1 TO i
      LET pn=pn+p(i,k) !列の和
   NEXT k
   PRINT i; pn

NEXT i

END

※計算の都合上、提示された漸化式の行と列を入れ替えています。(転置)



> オイラーの五角数定理だの母関数だのと解説されているが、
!分割数(オイラーの五角数定理)

LET N=30

DIM a(0 TO N),p(0 TO N)
MAT a=ZER
MAT p=ZER

LET i=0
LET j=i*(3*i-1)/2
DO
   IF MOD(i,2)=1 THEN !奇数なら
      LET a(j)=a(j)-1
   ELSE !偶数なら
      LET a(j)=a(j)+1
   END IF
   LET i=i+1
   LET j=i*(3*i-1)/2
LOOP WHILE j<=N

LET i=0
LET j=i*(3*i+1)/2
DO
   IF MOD(i,2)=1 THEN !奇数なら
      LET a(j)=a(j)-1
   ELSE !偶数なら
      LET a(j)=a(j)+1
   END IF
   LET i=i+1
   LET j=i*(3*i+1)/2
LOOP WHILE j<=N

LET p(0)=1
FOR i=1 TO N
   FOR j=0 TO i-1
      LET p(i)=p(i)-p(j)*a(i-j)
   NEXT j
NEXT i

FOR i=0 TO N !結果を表示する
   PRINT i; a(i); p(i)
NEXT i

END
 

戻る