• ベストアンサー

vba  組み合わせパターン表示

1,2,3,--,n-1,nからm個とる組み合わせのパターンを セル(1,1)から(nCm、nCm)に表示させる処理をVBAで記述 したいのですが、どうすればいいのでしょうか。 よろしくお願いします。

  • taktta
  • お礼率72% (1031/1430)

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

  • ベストアンサー
  • kigoshi
  • ベストアンサー率46% (120/260)
回答No.4

再帰呼び出しのアルゴリズムは「自分自身を呼び出す」わけですから、普通の上から下へ 読んでいくフローとはひと味違って、考えにくいところがあります(実は私もしばらくや ってなかったので今回少し手こずりました)。 各行の意味を書きます。 Const nStr As String = "あいうえおかきく" '←n個の文字列 Const m As Integer = 3 '←取り出す個数 Dim n As Integer '←ご質問文のn Dim rStr As String '←m個取り出した文字列を結合したもの Dim mRow As Integer '←エクセル表へ書き出す際の行番号 Dim Nest As Integer '←再帰呼び出しの深さ=rStrの何文字目に取り出すのか '----------------------- Sub combi() n = Len(nStr) 'nStrの文字列長をnに代入 If m > n Then Exit Sub 'nよりmが大きければ終了 rStr = String(m, " ") 'rStrにm個の空白を代入 Cells.ClearContents '書き出す表をクリア mRow = 0 '書き出す行番号0クリア Nest = 0 '再帰呼び出し深さ0クリア combiPr (0) 'サブルーチン combiPr を引数0で呼び出し End Sub '----------------------- Sub combiPr(n1) 'サブルーチン開始 引数はその時点での開始位置(nStrの何文字目まで処理したか) Dim mCol As Integer '←エクセル表へ書き出す際の列番号 For nn = n1 + 1 To n - m + Nest + 1 'nnを開始位置の次の文字から始めて残りの文字数の手前までFor~Nextを繰り返す Nest = Nest + 1 '再帰呼び出しを1カウントアップ Mid(rStr, Nest, 1) = Mid(nStr, nn, 1) 'rStrのNest番目にnStrのnn番目を代入 If Nest = m Then 'rStrに取り出したのがm文字目なら mRow = mRow + 1 'エクセル表の次の行へ For mCol = 1 To m 'rStrの1文字目からm文字目まで書き出す。 Cells(mRow, mCol).Value = Mid(rStr, mCol, 1) Next Else 'そうでなければ、つまり現在の開始位置(=nStrの何文字目まで処理したか)がm個まで達してなければ Call combiPr(nn) '現在の到達位置(nStrの何文字目まで処理したか)にnnをセットしてcombiPrを呼び出す(再帰呼び出し) End If Nest = Nest - 1'再帰呼び出しを1後退 Next End Sub 手順は原始的なものです。 あ~く まで書かれたカードを8枚ならべて3枚抜き出すことを考えればお解りになるで しょうか。 あ を一枚抜き出し、 い を抜き出し2枚目に置きます。 う を抜き出し、3枚目とします。←これを く まで繰り返します。 次に、い を戻して う を新たな2枚目とします。 え を抜き出し、3枚目とします。←これを く まで繰り返します。 の繰り返し・・・・ を行っているわけです。 ポイントは、1枚目を抜き出すのは か までだという点です。 き まで抜き出したら(く までしかないので)3枚目のカードがなくなります。 同様に2枚目は き までしか抜き出してはいけません。 これが「For nn = n1 + 1 To n - m + Nest + 1」の「n - m + Nest + 1」の部分の意味です。 テキストベースのみの説明なので伝えにくいのですが、不明な点があったら補足説明しますの で、またおたずねください。

taktta
質問者

お礼

こんなにもていねいな説明にとても感謝します。 おかげでおおよその意味はつかめました。あと数回読み直し納得がいくようにいたします。

その他の回答 (3)

  • kigoshi
  • ベストアンサー率46% (120/260)
回答No.3

> この combiというプロシジャを起動すれば、8個から3個取り出す組み合わせが表示されるはずなんですよね。 そうです。 > しかし、何も表示されません。エラーは何もでませんが。 パラメータとか指摘する必要ありますか。 特にパラメータなど指定する必要はありません。 Excel2002/標準モジュールにて確認しましたが当方の環境では56通りの組合せが表示されます。

taktta
質問者

お礼

やり直したらうまく表示されました。ご回答どうもありがとうございました。

taktta
質問者

補足

ソフト動作をシュミレートしておおよそどのような 動きをしているのか、説明くださればありがたい。 変数の定義など combi(0)で0を入れる意味は

  • kigoshi
  • ベストアンサー率46% (120/260)
回答No.2

再帰(的)呼び出しのアルゴリズムになると思います。 以下のソースでいかがでしょうか。 Const nStr As String = "あいうえおかきく" '←n個の文字列 Const m As Integer = 3 '←取り出す個数 Dim n As Integer Dim rStr As String Dim mRow As Integer Dim Nest As Integer '----------------------- Sub combi() n = Len(nStr) If m > n Then Exit Sub rStr = String(m, " ") 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 Mid(rStr, Nest, 1) = Mid(nStr, nn, 1) If Nest = m Then mRow = mRow + 1 For mCol = 1 To m Cells(mRow, mCol).Value = Mid(rStr, mCol, 1) Next Else Call combiPr(nn) End If Nest = Nest - 1 Next End Sub

taktta
質問者

補足

この combiというプロシジャを起動すれば、8個から3個取り出す組み合わせが表示されるはずなんですよね。 しかし、何も表示されません。エラーは何もでませんが。 パラメータとか指摘する必要ありますか。

  • mina5
  • ベストアンサー率44% (4/9)
回答No.1

問題は(nCm、nCm)でなく(nCm、m)でしょうね。

関連するQ&A

  • EXCEL VBAで組合せを作るには

    EXCEL VBAで組合せを作る方法を考えているのですが、なかなか思い付かず質問させて頂いています。 例) 1 2 3 4 5 … nという数字があり、そこから抜き取り組合せを作る。 ・2個ずつの組合せ 1と2 1と3 1と4 という感じで組合わせて行くが、2と1というような逆のパターンは除外する。 ・3個ずつの組合せ、4個ずつの組合せ…と最終n-1個(n個全てを抜取る組合せは1パターンしかないので、あえて作らなくてもよいのではと思っています)まで組合せを作って行く。 という内容です。 抜き取りたい数字の個数が、いつも決まった数ではなく、それに対応したものが考えきれなくてつまづきました。 どうかよろしくお願いいたします。

  • エクセルで組合せのパターンを表示したい

    12人から9人を選ぶ組合せのパターンをすべて表示させる 方法はないでしょうか?パターン数はCONBIN関数で220通り と求められました。この220通りを実際に表示させたいの です。エクセル上級者ではないので、簡単なマクロだと 助かりますが、いいアイデアがあれば教えてください。 よろしくお願いします。

  • 2つのセルの組み合わせ

    図のようなコードをもとに、セルの文字を連結させて商品管理番号をつくりたいと考えています。 (11A1、11A2・・・、12A1、12A2、・・・14A6) サンプルで出してありますが、このほかにもいくつかあります。 手動では大変なため、vbaにて処理をしたいと考えておりますが、 組み合わせなのか順列なのか、今ひとつ見当がつかず、どのようにvbaを記述すれば スッキリするのか悩んでおります。 for nextでの処理で変数を用いれば可能なのでしょうが・・・ 変数が1つなのか、2つなのか、どうもスッキリしません。 記述について、アドバイスいただければと思います。 不備がありましたらご指摘ください。よろしくお願いします。

  • 組合せ

    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); }

  • エクセルで2つの値の組合せによる値を表示するには

    うまくつたわるかわかりませんが、以下のようなことができる関数等を教えてください。 基礎データとして、以下のような表を用意(カンマで記述しますが、実際はエクセルの表で書いています) 大項目,中項目,パターン あああ,わわわ,パターン1 あああ,ををを,パターン2 いいい,わわわ,パターン3 いいい,ををを,パターン4 パターンは、大項目と中項目の組合せから決まります。 別のシートで、大項目と中項目を入力すると、あるセルにパターンを表示(パターン1から4のいづれか)させることがしたいです。大項目と中項目の組合せを変えると、動的にパターンが変化(確定表示)するイメージです。 関数で実現できない場合は、その他の実現方法をご教授ください。よろしくお願いします。

  • 組み合わせ

    n個の集合からp個を取る組み合わせの総数を出力するプログラムなんですが nCp=n!/p!(n-p)!という式を使い #include<stdio.h> int kaijo(int m); int comb(int n,int p); int main(void) { int i,j; printf("n="); scanf("%d",&i); printf("p="); scanf("%d",&j); printf("comb(%d,%d)=%d\n",i,j,comb(i,j)); } int kaijo(int m) { if(m>0) return(m*kaijo(m-1)); else return 1; } int comb(int n,int p) { if(n>0) return((n*kaijo(n-1))/(p*kaijo(p-1)*(n-p)*kaijo(n-p-1))); else return 1; } と書いてみたのですがこれではnが大きいとC言語のint型で扱える最大値を超えてしまい正しい結果が出力されません。  そこでint型を使ったままでnやpが大きい場合でもある程度出力できるようにしたいのですがどう改良したらよいのでしょうか? おそらくnCp=n*(n-1)*・・・*(n-p+1)/p!という式を使うのですがよく分かりません。よろしくお願いします。

  • Excel VBA 組み合わせパターン

    A1~A5 に、順に 「あ」「い」「う」「え」「お」が入っています。 B1に「3」を入れたとき C1以降、各セル1文字ずつで、 あああ ああい ああう …(略) おおえ おおお といった具合に表示させたいのです。 VBAで簡単にできるでしょうか。 ※A列のデータ数は変動します。

  • 組み合わせ プログラミング

    c言語についてです os linux コンパイラはgccです long fact2(int n,int m)を作成してfact2(n,m)を使って組み合わせを計算するプログラムを作れという問題で下記のように作りましたが コンパイルできません. エラーメッセージは 2-1.c:14: error: 関数 `fact2' への引数が少なすぎます 2-1.c:14: error: 関数 `fact2' への引数が少なすぎます 2-1.c:14: error: 関数 `fact2' への引数が少なすぎます です 関数のとこが違うと思うですが どうしたらいいのかわかりません それともなにか他のとこが違うのでしょうか? #include <stdio.h> long fact2(int,int); main() { int n, m; long c; printf(" nCm (n>m) \n"); printf("input n m ="); scanf("%d %d",&n, &m); c =fact2(n) / (fact2(m) * fact2(n-m)); printf("%dC%d = %ld\n",n,m,c); } long fact2(int n,int m) { int i; long c=1; for(i=1; i<=n; i++) c*=i; return(c); }

  • 物を選ぶパターン数について

    パターンを数える方法がわかりません 10個の石の中から10個の石を選ぶ(順不同)のは1パターンです 11個の石の中から10個の石を選ぶのは11パターンあります そこまではわかるのですが 12個の石の中から10個の石を選ぶのは何パターンあるのかがわかりません また、m個の中からn個の石を選ぶパターン数を求める方式があるのでしょうか? 教えてください よろしくお願いします

  • この問題での順列組み合わせの使い方は?

    n進数m桁の数字列を考える。 全部でn^m通りのパターンがある。 このうち、一回も現れない数字のあるパターンQは何通りか。 自分で立てた問題です(というか興味があるので知りたい) けど、どうしても分かりません。 解き方を教えて下さい。 以下は自分の考えた履歴です --- ある数字に着目して、それが選ばれないパターンは(n-1)^m通り これを数字の種類だけn倍すると、同じパターンを重複して数えてしまう気がする。 どうやって除去するか? --- 【n>mのとき】 m=1のとき、Q=n-1通り m=2のとき、 一回目と二回目で数字が同じパターンはn通り 異なるパターンはn*(n-1)通り ・・・ここから先が分からない

専門家に質問してみよう