数の分割[b][color=#0000ff]decompose,divide,partition[/color][/b]とは、[br]その数自身または、それ以外の数の和の組み合わせの式のことで、[br]分割数はその総数です。[br]たとば、3の分解は3,2+1,1+1+1があり、分割数は3(通り)です。[br][br][br]・例9[br]xにxpを代入すると、(x[sup]p[/sup])[sup]n[/sup]=x[sup]np[/sup]から、[br]例1の母関数f(xp)は、[b]1/(1-[b]x[sup]p[/sup][/b])=1+x[sup]p[/sup]+x[sup]2p[/sup]+.....[b]x[sup]kp[/sup]+[/b][/b] [br]n個からp個単位で取り出すことを表します。このpを1,2,3,4,....として母関数をかけたものは[br][br][size=150][b]1/{(1-[b]x[sup]1[/sup][/b])[/b][b](1-[b]x[sup]2[/sup][/b])[/b][b](1-[b]x[sup]3[/sup][/b])[/b][b](1-[b]x[sup]4[/sup][/b]).....}[b]=Σ[b]x[sup]k[/sup][b][b]Σ[b]x[sup]2k[/sup][b][b]Σ[b]x[sup]3k[/sup][b][b]Σ[b]x[sup]4k[/sup][b][b]Σ..... = 1 + 1x+2x[sup]2[/sup]+3x[sup]3[/sup]+5x[sup]4[/sup]+7x[sup]5[/sup]+....[br][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/size][size=150][br][color=#0000ff]nの和分解[b]decompose[/b]の数はx[sup]n[/sup]の係数に等しい。[br][/color][/size][b][br](検証)母関数の係数を分離したリストを作る[br]1/(1-[b]x[sup]1[/sup][/b])=1+[b][b]x[sup]1[/sup][/b][/b]+x[sup]2[/sup]+[b]x[sup]3[/sup]+[/b][b]x[sup]4[/sup][b][b]+[/b][b]x[sup]5 [/sup][/b][/b][/b][/b] -> [1,1,1,1,1,1] [br][b]1/(1-[b]x[sup]2[/sup][/b])=1+[b][b]x[sup]2[/sup][/b][/b]+x[sup]4[/sup][/b] -> [1,0,1,0,1,0] [br][b]1/(1-[b]x[sup]3[/sup][/b])=1+[b][b]x[sup]3[/sup][/b][/b][/b] -> [1,0,0,1,0,0] [br][b]1/(1-[b]x[sup]4[/sup][/b])=1+[b][b]x[sup]4[/sup][/b][/b][/b] ->[1,0,0,0,1,0] [br][b]1/(1-[b]x[sup]5[/sup][/b])=1+[b][b]x[sup]5[/sup][/b][/b][/b] ->[1,0,0,0,0,1] [br]右辺の積は[b]1+[b][b]x[sup]1[/sup][/b][/b]+2x[sup]2[/sup]+3[b]x[sup]3[/sup]+5[/b][b]x[sup]4[/sup][b][b]+7[/b][b]x[sup]5[/sup][/b][/b][/b][/b] +.......[br]x[sup]4[/sup]の係数は5。これは、4の[4, 3+1, 2+2, 2+1+1, 1+1+1+1]の5通りの和分解に一致する。[br]x[sup]5[/sup]の係数は7。これは、5の[5, 4+1, 3+2, 3+1+1,2+2+1,2+1+1+1,1+1+1+1+1]の7通りの和分解に一致する。[br][br][br][color=#9900ff][b][u][size=150]質問:例9の考え方を使って、整数Nの和分解をする関数を作るにはどうしたらようでしょうか。[br][/size][/u][/b][/color][br]多項式の係数を取り出します。つぎに逆順にして繰り上がらないx進法(xが巨大)として[br]係数をかけ算します。筆算でもできますよ。[br][1,1,1,1,1,1] reverse-> 111111[br][1,0,1,0,1,0] reverse-> 010101[br][1,0,0,1,0,0] reverse-> 001001[br][1,0,0,0,1,0] reverse-> 010001[br][1,0,0,0,0,1] reverse-> 100001[br]10になっても繰り上がりせずに、111111×010101(mod 1000000) = 332211[br]332211×1001(mod 1000000)=543211[br]543211×10001(mod 1000000)=653211[br]653211×100001(mod 1000000)=753211となります。つまり、[br][br][b]111111*10101*1001*10001*100001 % 1000000= 753211[br][/b][br]このreverseして、[1,1,2,3,5,7]になりますね。[br]これで、1から5まで和分解の数がわかる係数の数列ができました。[br][br]このような発想でnを和分解する関数[b]decompo[/b](n)を作ってみよう。[br]ポイントは、1からnまでのそれぞれの倍数を表す母関数リスト[b]genef[/b]は[b]静的[/b]に作れます。[br]だから、宣言型、関数型プログラミングが向いています。[br][br]次に母関数のかけ算ですが、逆転してからかけ算して、最後にもとに戻すのは[br]筆算には向いています。プログラミングでは、あえて逆転せずにそのままできます。[br]係数リストの番号が、母関数の次数を表していると考えれば、0次の定数項が0番、[br]1次の係数がリストの1番、、、、と考えると、n次の係数はリストのn番となるからです。[br][br]n個の関数1の倍数の[b]genef[/b][0]からnの倍数の[b]genef[/b][n-1]までを全部かけ算して、[br]xnの係数を求めよう。[br]このかけ算は、かけ算の結果、[b]状態が変化する[/b]プロセスなので[br]動的な、通常の手続きのくり返し型のプログラミングが向いているでしょう。[br][b][IN]Python=========================================================[br][color=#0000ff]def decompo(n):[br] max_id = n+1[br] genef = [] # 反復後の母関数係数のリスト[br] indexs = [x for x in range(max_id)][br] for i in range(1,max_id):[br] genef.append(list(map(lambda x : 1 if x % i ==0 else 0, indexs)))[br] print(f"{n}の和分解をするために、母関数をかける。prev*current")[br] prev = genef[0] [br] # prevの初期値はgenefの先頭の母関数[br] for i in range(1,max_id-1):[br] ans = [0]*(3*n)[br] current = genef[i] #currentはgeneの1以上の母関数[br] print(f"prev = {prev},current = {current}")[br] for k in range(max_id): # current のk番を動かす[br] if current[k]==1:[br] for j in range(max_id): #prevをkけたシフトしてansに加算[br] ans[j + k] += prev[j][br] for l in range(max_id):[br] prev[l] = ans[l] #ansの内容をprevに必要な分だけコピー[br] print(f"関数積 {prev}から、{n} の分解数={ans[n]}")[br] return True[br][/color][br]decompo(4)[br]decompo(6)[br]decompo(9)[br][/b][OUT]=============================================[br]4の和分解をするために、母関数をかける。prev*current[br]prev = [1, 1, 1, 1, 1],current = [1, 0, 1, 0, 1][br]prev = [1, 1, 2, 2, 3],current = [1, 0, 0, 1, 0][br]prev = [1, 1, 2, 3, 4],current = [1, 0, 0, 0, 1][br]関数積 [1, 1, 2, 3, 5]から、4 の分解数=5[br]6の和分解をするために、母関数をかける。prev*current[br]prev = [1, 1, 1, 1, 1, 1, 1],current = [1, 0, 1, 0, 1, 0, 1][br]prev = [1, 1, 2, 2, 3, 3, 4],current = [1, 0, 0, 1, 0, 0, 1][br]prev = [1, 1, 2, 3, 4, 5, 7],current = [1, 0, 0, 0, 1, 0, 0][br]prev = [1, 1, 2, 3, 5, 6, 9],current = [1, 0, 0, 0, 0, 1, 0][br]prev = [1, 1, 2, 3, 5, 7, 10],current = [1, 0, 0, 0, 0, 0, 1][br]関数積 [1, 1, 2, 3, 5, 7, 11]から、6 の分解数=11[br]9の和分解をするために、母関数をかける。prev*current[br]prev = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],current = [1, 0, 1, 0, 1, 0, 1, 0, 1, 0][br]prev = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5],current = [1, 0, 0, 1, 0, 0, 1, 0, 0, 1][br]prev = [1, 1, 2, 3, 4, 5, 7, 8, 10, 12],current = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0][br]prev = [1, 1, 2, 3, 5, 6, 9, 11, 15, 18],current = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0][br]prev = [1, 1, 2, 3, 5, 7, 10, 13, 18, 23],current = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0][br]prev = [1, 1, 2, 3, 5, 7, 11, 14, 20, 26],current = [1, 0, 0, 0, 0, 0, 0, 1, 0, 0][br]prev = [1, 1, 2, 3, 5, 7, 11, 15, 21, 28],current = [1, 0, 0, 0, 0, 0, 0, 0, 1, 0][br]prev = [1, 1, 2, 3, 5, 7, 11, 15, 22, 29],current = [1, 0, 0, 0, 0, 0, 0, 0, 0, 1][br]関数積 [1, 1, 2, 3, 5, 7, 11, 15, 22, 30]から、9 の分解数=30[br][br]例10 [br]6色の色紙がそれぞれ6枚ずつあるとする。これから重複を許して6枚選ぶ組み合わせを求める。[br]同じ母関数を6回かけよう。[br][b](1+[b][b]x[sup]1[/sup][/b][/b]+x[sup]2[/sup]+[b]x[sup]3[/sup]+[/b][b]x[sup]4[/sup][b][b]+[/b][b]x[sup]5[/sup][/b][/b][/b][/b]+[b][b]x[sup]6[/sup])[/b][/b][sup]6 [/sup]を展開して、x[sup]6[/sup]の係数をもとめればよいね。[br]6=6, 5+1, 4+2, 4+1+1, 3+3, 3+2+1, 3+1+1+1, 2+2+2, 2+2+1+1, 2+1+1+1+1,1+1+1+1+1+1から多項定理から、[br]6C1+6*5+6*5+6*5C2+6!/(3!3!)+6P3+6*5C3+6!/(2!2!2!)+6C2*4C2+6C1*5C4+6C6[br]=6+30*2+60+20+120+60+15+90+30+1=462通りだね。[br][br][color=#9900ff][b][u][size=150]質問:例10の6種6枚から重複して6選ぶ重複組み合わせをコードで求めるにはどうしますか。[br][/size][/u][/b][/color][br]例9では母関数がnだけあったけれど、重複組み合わせでは、同じ1つの母関数をn乗するだけだから、[br]むしろ、しくみは簡単になるね。[br]母関数の係数であるgeneリストは定数項もあるので、1をn+1個並べたもの。[br]かならずかけ算になるので、ifは不要になるし、1倍だから、[br]シフトするだけというしくみも同じになるね。[br][br]#[IN]Python[br][color=#0000ff]def dblcombi(n):[br] max_id = n+1[br] gene = [1]*max_id[br] print(f"{n}の重複組み合わせを求めるために、母関数を{n}回かける。")[br] prev = gene [br] # prevの初期値はgenefの先頭の母関数[br] for i in range(1,max_id-1):[br] ans = [0]*(3*n)[br] print(f"prev^{i} = {prev}")[br] for k in range(max_id): #current のk番を動かす[br] for j in range(max_id): #prevをkけたシフトしてansに加算[br] ans[j + k] += prev[j][br] for l in range(max_id):[br] prev[l] = ans[l] #ansの内容をprevに必要な分だけコピー[br] print(f"prev^{n} = {prev}から、{n}枚の組み合わせ数={ans[n]}")[br] return True[br][/color][br]dblcombi(6)[br]dblcombi(8)[br]#=========================[br][OUT][br]6の重複組み合わせを求めるために、母関数を6回かける。[br]prev^1 = [1, 1, 1, 1, 1, 1, 1][br]prev^2 = [1, 2, 3, 4, 5, 6, 7][br]prev^3 = [1, 3, 6, 10, 15, 21, 28][br]prev^4 = [1, 4, 10, 20, 35, 56, 84][br]prev^5 = [1, 5, 15, 35, 70, 126, 210][br]prev^6 = [1, 6, 21, 56, 126, 252, 462]から、6枚の組み合わせ数=462[br]8の重複組み合わせを求めるために、母関数を8回かける。[br]prev^1 = [1, 1, 1, 1, 1, 1, 1, 1, 1][br]prev^2 = [1, 2, 3, 4, 5, 6, 7, 8, 9][br]prev^3 = [1, 3, 6, 10, 15, 21, 28, 36, 45][br]prev^4 = [1, 4, 10, 20, 35, 56, 84, 120, 165][br]prev^5 = [1, 5, 15, 35, 70, 126, 210, 330, 495][br]prev^6 = [1, 6, 21, 56, 126, 252, 462, 792, 1287][br]prev^7 = [1, 7, 28, 84, 210, 462, 924, 1716, 3003][br]prev^8 = [1, 8, 36, 120, 330, 792, 1716, 3432, 6435]から、8枚の組み合わせ数=6435