マクロで組み合わせの数を求める計算(再帰的)

このQ&Aのポイント
  • マクロを使ってセルに組み合わせ計算を行う方法について質問があります。
  • マクロのK関数を用いて組み合わせ計算を再帰的に行うことができますが、K関数の原理やK=1という定義について理解できません。
  • 具体的な計算例を挙げながら、再帰的な組み合わせ計算の原理について教えていただけますか?
回答を見る
  • ベストアンサー

マクロで組み合わせの数を求める計算(再帰的)

Ms-excelで下記のマクロを作ると「=K(n,i)」と適当なセルに入れることで、組み合わせ計算(=高校の教科書の表記では nCi )を行えるようですがどういう原理で組み合わせ計算をしているのか理解できないため質問します。 ------------ Function K(n, i) K = 1 If i > 0 Then K = (n - i + 1) / i * C(n, i - 1) End If End Function ------------ 以下高校の教科書に沿ってK(n, i)を nCi と書きますが、 例えば5C5を求めるとき上のプログラムだと、 5C5 = 5C4*1/5 5C4 = 5C3*1/2 5C3 = 5C2*1 5C2 = 5C1*2 (以下i>0となるためストップ) とさかのぼって計算して(再帰的定義?)いるようですが、5C1(マクロでK(5, 1)の値 )が定義されていない以上はさかのぼっていっても値が決まらないように思いますがどういう原理で組み合わせ計算をしているのでしょう?またK=1と定義する意味はあるんでしょうか?

  • r_faq
  • お礼率82% (37/45)

質問者が選んだベストアンサー

  • ベストアンサー
  • nattocurry
  • ベストアンサー率31% (587/1853)
回答No.2

>K = (n - i + 1) / i * C(n, i - 1) これは、 K = (n - i + 1) / i * K(n, i - 1) の間違いということで良いですか? i>0だから5C2でストップしているからいけないのです。 i>0でも5C1は求められます。 5C1の計算のために5C0を求める必要がありますが、 K(5,0)の場合、 最初にK=1という計算があり、i>0ではないから、if文が実行されないだけです。 つまり、K(5,0)は1ということになります。 だから、K(5,1)も求めることが出来ます。 i>0じゃないとKの関数を使えない、と思い込んでしまったことがいけなかったですね。

r_faq
質問者

お礼

ご回答ありがとうございます。参考になりました。

その他の回答 (1)

  • f272
  • ベストアンサー率46% (8018/17137)
回答No.1

> 5C1(マクロでK(5, 1)の値 )が定義されていない でも,5C0の値は1と定義されてるよね。 > またK=1と定義する意味はあるんでしょうか? それが5C0です。

r_faq
質問者

お礼

ご回答ありがとうございます。参考になりました。

関連するQ&A

  • 再帰・組み合わせ

    新しく再帰という概念を習い始めたのですが、組み合わせを求めるやり方がわかりません 組み合わせの公式通り(nCk → n!/k!(n-k)!)、例えば4C2なら答えは6通りになるのはわかるのですが、 public static int combinations(int n, int k){ if(k==n){ return 1; }else if(k=1){ return n; }else if(0<k && k<n){ combinations(n-1, k-1) + combinations(n-1, k) ←これで出来るらしいのです } } combinations(n-1, k-1)は意味がわかるのですが、combinations(n-1, k)これが組み合わせの公式にどうあてはまっているのかがわからず、 そして何故足してるのかがよくわかりません。どなたかお解かりになればお願いします

    • ベストアンサー
    • Java
  • Excelマクロの配列計算が♯VALUE!となる

    Excelマクロの複素数を扱う配列計算がエラーとなります.  下記HPからマクロを標準モジュールに取り込み,以前のQAで助けて頂き 一部修正により動作するようになりました. しかし,このマクロで定義した「 IMINVERS 」関数を実行すると,大きい 配列では「#VALUE!」となってしまいます. 助けて頂けませんか! http://www.geocities.jp/tomtomf/denki/AC2/ac2.htm http://www.geocities.jp/tomtomf/denki/AC1/ac1.htm 〔問題の現象〕  整数の行列(6×6)以上の配列計算は「#VALUE!」となる.  複素数の行列(5×5)以上の配列計算は「#VALUE!」となってしまう. 小さい配列では正しく計算できているので,手順には問題ないようにみえます. どこに問題があるのでしょうか. 問題の「 IMINVERS」関数に関するマクロは以下の通りです。 ----------------------------------------------------------- Public Function IMABSa(a As Variant) As Variant IMABSa = Application.WorksheetFunction.ImAbs(a) End Function Public Function IMDIVa(a As Variant, b As Variant) As Variant IMDIVa = Application.WorksheetFunction.ImDiv(a, b) End Function Public Function IMPRODUCTa(ParamArray a()) As Variant IMPRODUCTa = Application.WorksheetFunction.ImProduct(a) End Function Public Function IMPRODUCTb(a As Variant, b As Variant) As Variant IMPRODUCTb = Application.WorksheetFunction.ImProduct(a, b) End Function Public Function IMSUBa(a As Variant, b As Variant) As Variant IMSUBa = Application.WorksheetFunction.ImSub(a, b) End Function Public Function IMSUMa(ParamArray a()) As Variant IMSUMa = Application.WorksheetFunction.ImSum(a) End Function Public Function IMSUMb(a As Variant) As Variant IMSUMb = Application.WorksheetFunction.ImSum(a) End Function ----------------------------------------------------- Public Function IMINVERS(a As Range) As Variant Dim n As Integer, n1 As Integer, n2 As Integer Dim r1 As Integer, r2 As Integer, c As Integer Dim max As Variant Dim i As Integer Dim m() As Variant Dim inm() As Variant Dim rr As Integer, cc As Integer Dim no As Integer, ex As Variant n1 = a.Rows.Count n2 = a.Columns.Count n = n1 ReDim inm(1 To n1, 1 To n2) For rr = 1 To n1 For cc = 1 To n2 If rr <> cc Then inm(rr, cc) = 0 Else inm(rr, cc) = 1 End If Next Next ReDim m(1 To n1, 1 To n2) m = a If n1 <> n2 Then IMINVERS = False Exit Function End If For r1 = 1 To n max = m(r1, r1) no = r1 If r1 < n Then For i = r1 + 1 To n If IMABSa(m(i, r1)) > IMABSa(max) Then max = m(i, r1) no = i End If Next If (r1 <> no) Then For i = 1 To n ex = m(r1, i) m(r1, i) = m(no, i) m(no, i) = ex Debug.Print m(r1, i), m(no, i) ex = inm(r1, i) inm(r1, i) = inm(no, i) inm(no, i) = ex Next End If End If max = m(r1, r1) For i = 1 To n m(r1, i) = IMDIVa(m(r1, i), max) inm(r1, i) = IMDIVa(inm(r1, i), max) Next For r2 = 1 To n If r1 <> r2 Then max = m(r2, r1) For i = 1 To n m(r2, i) = IMSUBa(m(r2, i), IMPRODUCTa(m(r1, i), max)) inm(r2, i) = IMSUBa(inm(r2, i), IMPRODUCTa(inm(r1, i), max)) Next End If Next Next IMINVERS = inm End Function ------------------------------------------------

  • ボックスから取り出た組み合わせの数

    計算式を教えてください。 ①~⑤のボックスに、それぞれ異なる部品が以下の個数入っています ①:[A,B,C] ②:[D,E,F] ③:[G,H] ④:[I,J,K] ⑤:[L,M,N] これらを各ボックスから1つずつ選択して、ロボットを作るとした時に、 見た目の組み合わせは3*3*2*3*3 だと思うのですが、 ここから、 ・1箇所のみが違って、残りの4箇所は同じ組み合わせ ・2箇所のみが違って、残りの3箇所は同じ組み合わせ が計算式とともにわかりたいです。

  • エクセルマクロで定義した関数が動きません

    以前にマクロの記述について教えて頂いた件の続きになります. ご指導頂いたとおりExcelマクロで複素数を扱う関数を下記HPから 標準モジュールにコピペしました.今度は正しくコピーできたと思いますが, 実行するとエラーになります. 標準の組込み関数を用いて「実数」の行列を計算すれば正しく 計算できますが,当然ながら「複素数」は計算できません. この「複素数」を扱う新しく定義した関数が動かない理由, 「End if に対するifブロックがありません」とか 計算結果が「#VALUE!」となってしまうのは何故でしょうか? マクロの記述内容はほとんど理解できないのですが, どなたか助けて頂けませんか! ちなみにエクセルは2016版です. http://www.geocities.jp/tomtomf/denki/AC2/ac2.htm http://www.geocities.jp/tomtomf/denki/AC1/ac1.htm 以下はコピー定義した「 IMMULT」関数と「 IMINVERS」関数のマクロです. Public Function IMMULT(a As Range, b As Range) As Variant Dim r1 As Integer, r2 As Integer, c1 As Integer, c2 As Integer, nn As Integer Dim r As Integer, c As Integer Dim cr As Integer, cc As Integer Dim n As Integer Dim mm() As Variant r1 = a.Rows.Count r2 = b.Rows.Count c1 = a.Columns.Count c2 = b.Columns.Count If (c1 = r2) Then nn = c1 Else Exit Function End If cr = r1 cc = c2 ReDim mm(1 To cr, 1 To cc) For r = 1 To cr For c = 1 To cc mm(r, c) = 0 For n = 1 To nn mm(r, c) = IMSUMa(mm(r, c), IMPRODUCTa(a.Cells(r, n), b.Cells(n, c))) Next Next Next IMMULT = mm End Function Public Function IMINVERS(a As Range) As Variant Dim n As Integer, n1 As Integer, n2 As Integer Dim r1 As Integer, r2 As Integer, c As Integer Dim max As Variant Dim i As Integer Dim m() As Variant Dim inm() As Variant Dim rr As Integer, cc As Integer Dim no As Integer, ex As Variant n1 = a.Rows.Count n2 = a.Columns.Count n = n1 ReDim inm(1 To n1, 1 To n2) For rr = 1 To n1 For cc = 1 To n2 If rr <> cc Then inm(rr, cc) = 0 Else inm(rr, cc) = 1 'End If Next Next ReDim m(1 To n1, 1 To n2) m = a If n1 <> n2 Then IMINVERS = False Exit Function End If For r1 = 1 To n max = m(r1, r1) no = r1 If r1 < n Then For i = r1 + 1 To n If IMABSa(m(i, r1)) > IMABSa(max) Then max = m(i, r1) no = i End If Next If (r1 <> no) Then For i = 1 To n ex = m(r1, i) m(r1, i) = m(no, i) m(no, i) = ex Debug.Print m(r1, i), m(no, i) ex = inm(r1, i) inm(r1, i) = inm(no, i) inm(no, i) = ex Next End If End If max = m(r1, r1) For i = 1 To n m(r1, i) = IMDIVa(m(r1, i), max) inm(r1, i) = IMDIVa(inm(r1, i), max) Next For r2 = 1 To n If r1 <> r2 Then max = m(r2, r1) For i = 1 To n m(r2, i) = IMSUBa(m(r2, i), IMPRODUCTa(m(r1, i), max)) inm(r2, i) = IMSUBa(inm(r2, i), IMPRODUCTa(inm(r1, i), max)) Next End If Next Next IMINVERS = inm End Function

  • エクセルマクロでの計算について(2007)

    エクセルマクロ初心者です。 試行錯誤しながら作成しています。 セルB1には直接計算式を入れており(=(480+(A1)*10)/480*I1) その結果次第(70以下)でセルC1に計算結果(=(75-B1)*.48)をいれて 70より大きければセルC1に"-"を入れたいのですが上手く計算してくれません。 この処理を約65個のセルにしようと思っています。(セルの列はバラバラです) どうすればよいかご教示ください。 ちなみに現在作成している文は Private Sub 計算_Click() Worksheets("sheet2").Select If Range("B1").Value <= 70 Then Range("C1").Formula = "=(75 - (B1)) * 0.48" Else: Range("C1").Value = "-" End If End Sub よろしくお願いいたします。

  • 組合せ

    2個の整数m,n(m≧n)をキーボートから受け取って、m個の相異なる物の中からn個取り出す組合せの数を計算するプログラムを作っているんですが、下のプログラムだと、13の階乗でオーバーフローしてしまいました。combination関数を使わずに、13の階乗を計算したいのですが…。 13!/(k!(13-k)!)で、13!でオーバーフローなので、13!/k!=(k+1)×…×13を計算すればいいのは分かるのですが、どういう関数を定義すればいいのかわかりません。 ヒントやアドバイス頂けると、助かります。 よろしくお願いします。 #include <stdio.h> void main(void) {long m,n; long fact(long); while(scanf("%ld,%ld",&m,&n)!=EOF) printf("comb(%ld,%ld)=%ld\n",m,n, fact(m)/(fact(n)*fact(m-n))); } long fact(long k) {long i,f; f=1; for (i=1;i<=k;i=i+1) f=f*i; return(f); }

  • 組み合わせを抽出するために使う再帰呼び出しについて

    1,2,3,4,5の数列から3の数の組合せをワークシートに表示するプログラムを作っています。 このソースは以前他の質問に載っていたものを自分用に多少アレンジしたものです。構造は再帰呼び出しを使って、123、124、125、134、135、145、234、235…345という形で結果を出力します。いろいろと試してみて、計算結果は正しいとわかったのですが、デバックをしていて1つどうしても理解できないことがありました。計算結果が145から234になるとき、カーソルがSub combiPrのEnd subを指したあと直前のEnd ifに移ります。その後Forに移って234以降の計算を始めます。どうしてEnd Subからこのような動作をするのかわかる方いらっしゃいましたら是非ワケを教えてください。よろしくお願いしますm(_ _)m Const m As Integer = 3 '←取り出す個数 Const n As Integer = 5 '←サンプル数 Dim rStr As String Dim mRow As Integer Dim Nest As Integer Dim A(10) As Variant Sub combi() Cells.ClearContents mRow = 0 Nest = 0 combiPr (0) End Sub Sub combiPr(n1) Dim mCol As Integer For nn = n1 + 1 To n - m + Nest + 1 Nest = Nest + 1 A(Nest) = nn If Nest = m Then mRow = mRow + 1 For mCol = 1 To m Worksheets(1).Cells(mRow, mCol).Value = A(mCol) Next Else Call combiPr(nn) End If Nest = Nest - 1 Next nn End sub

  • 再帰構造のアルゴリズムで困っています。

    最近プログラミングを勉強し始めた者です。 教科書とWebを使って勉強しているのですが、なかなか厳しいです。 初歩的な質問であると思いますがお許しください。 フィボナッチ数列の8番目の数字を再帰構造を用いて表示させるプログラムを作りました。 Sub saikikouzou() n = 8 Cells(1, 1) = keisan(n) End Sub Function keisan(n) If n < 3 Then keisan = 1 Else keisan = keisan(n - 1) + keisan(n - 2) End If End Function 一般的にフィボナッチ数列と言われると「1.1.2.3.5.8.13.21」という数列であると理解しています。上記のプログラムもそのつもりで作成しました。 しかし今は「1.2.3.5.8.13.21.34」という数列の8番目を再帰構造を使って求めたいと考えています。 つまり、最初の数字を「1,1…」と始まるのではなく「1.2…」と始めたいのです。 私のプログラムだと、 If n < 3 Then keisan = 1 の部分で最初の数字が「1.1」と決めているため、良くないことは理解できましたが、どうすれば「1.2…」と始められるかが分かりません。 まだこの単元を消化しきっていないため、質問内容もままならない点がありますが、ご理解できましたら是非回答をよろしくお願いします。

  • 組み合わせの問題について

    組み合わせに関する問題で質問があります。 ∑n_C_k = 2^n  (※∑はk=0からnまで) の証明がわかりません。 帰納法をつかってやるのかなと試してみたのですが、 n=kが成立すると仮定してn=k+1を計算するところで 詰まってしまいました。 よろしくお願いします。

  • 組み合わせの数え上げで困っています。

    組み合わせの数え上げが難しいので、計算のお伺いをいたします。 ビンゴゲームで、1から75の数字を用いたカードを作成します。 通常は、B/I/N/G/Oの縦列にそれぞれ5個(ただしNは4個)の数字を出して N以外は15C5の60倍、Nは15C4の24倍という計算が成り立つと思いますが、 海外において実際に存在するビンゴカードに以下のようなものがあります。 (1)1つのマスに数字が2個入っている。 (2)マスを構成する2個の数字、どちらが選ばれてもそのマスは塗られたものとする。 なので、48個の数字が印刷されたビンゴカードがありますが、2個のワンセットが逆になっても良いが、配列上は別となるため、実質的な組み合わせの計算が難しくなってしまいました(完全バラなら15C10の720倍&15C8の336倍をベースに求められる)。 どのように計算して、トータル何通りあるのでしょうか。 ご教示いただければと存じますので、よろしくお願いいたします。 (当然の前提ですが、B列は1から15、I列は16から30、N列は31から45、G列は46から60、O列は61から75の数字が使われます)