質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

4回答

2845閲覧

VBA nCrの列挙

Uuas14088

総合スコア0

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2020/07/29 09:05

編集2020/07/29 09:20

似たような質問が過去にあるかと思いますが、初心者であるためご容赦いただけたらと思います。宜しくお願い致します。

Excel vbaでnCrの組み合わせを全て列挙するものコードを考えています。
リストとして1-10があり、指定したrを抽出した組み合わせを表示するようなものです。
例 r=2

3 1+2
4 1+3
5 1+4
:
r=3

6 1+2+3
7 1+2+4
:

For文で繰り返すことで書いていましたが
調べると再帰関数やフィボナッチを考慮して
書くことができるとのことでぜひともどなたかご教示いただけたらと思います。
何卒よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2020/07/29 09:16

説明不足すぎて意味不明です
Uuas14088

2020/07/29 09:21

申し訳ございません。編集途中で投稿がされてしまっためです。
guest

回答4

0

ミスです消去します。

投稿2020/08/04 23:40

編集2020/08/04 23:41
tosi

総合スコア553

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんなもんかな?
シートに書き出します。

ちなみに再帰ルーチン中のループをnからstep-1でやっているのは
こうすると処理中は配列要素数をチェックする必要がないからです。
ただしこのため処理結果のリストが1からはじまりません。

補足(2020/08/05):
下のサンプルはn=10, r=3の時だけです。r=1~10のすべての組み合わせを得たい場合は、
呼び出し元にてfor文等を使い、rを1から10まで変化させてnCrを呼び出してください。

Option Explicit ' ' グローバル ' Dim rx As Long Dim elm As Variant ' ' 呼び出し元 ' Private Sub CommandButton1_Click() elm = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ' 処理対象の配列。※0はindex調整のダミー rx = 1 ' 結果書き込み行位置 Call nCr(10, 3, "") ' n=10, r=3。 End Sub ' ' 再帰ルーチン ' Private Function nCr(ByVal n As Long, ByVal r As Long, ByVal txt As String) If (r = 0) Then ' 再帰の底 rx = rx + 1 ' 書き込み行位置 Me.Cells(rx, "B") = Mid$(txt, 2) ' 先頭"+"を除いてシートに書き込み。 Else Dim ix As Long For ix = n To 1 Step -1 Call nCr(ix - 1, r - 1, "+" & elm(ix) & txt) ' 自分より右にある要素のすべての組み合わせ Next End If End Function

投稿2020/07/31 01:24

編集2020/08/05 01:44
h.horikoshi

総合スコア505

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

依頼と少し違う感じかも知れませんが、こんなのではどうでしょうか。A列に結果書き込まれます。

VBA

1Option Explicit 2'変数域 3Private lRow As Long 4Private lCol As Long 5Private giLayer As Integer 6Private giWorkLayerMax As Integer 7'定数域 8Private Const giCountMax As Integer = 10 9Private Const giLayerMax As Integer = 3 10' *********************************************** 11' 開始 12' *********************************************** 13Private Sub Test_Sample_Miniature() 14 Dim iX As Integer 15 Range("A:A").Clear 16 lRow = 0 17 lCol = 1 18 For iX = 1 To giLayerMax 19 giLayer = 0 20 giWorkLayerMax = iX 21 lRow = lRow + 1 22 Cells(lRow, lCol) = "(r = " & iX & ")" 23 Call 自己参照(0, "") 24 Next 25End Sub 26' *********************************************** 27' 自己参照 28' *********************************************** 29Private Function 自己参照(iLayer As Integer, strPara As String) As Boolean 30 Dim iX As Integer 31 Dim intWorkLay As String 32 Dim strWorkPar As String 33 giLayer = giLayer + 1 34 intWorkLay = giLayer 35 strWorkPar = strPara 36 For iX = 0 To giCountMax 37 If giLayer < giWorkLayerMax And iX <> giCountMax Then 38 If strWorkPar = "" Then strPara = iX + 1 Else strPara = strWorkPar & "+" & iX + 1 39 Call 自己参照(iLayer, strPara) 40 giLayer = giLayer - 1 41 Else 42 If iX <> giCountMax Then 43 lRow = lRow + 1 44 strPara = strWorkPar & "+" & iX + 1 45 Cells(lRow, lCol) = strPara 46 End If 47 End If 48 Next 49End Function

(追記)

VBA

1Option Explicit 2'変数域 3Private lRow As Long 4Private lCol As Long 5Private giLayer As Integer 6Private giWorkLayerMax As Integer 7'定数域 8Private Const giCountMax As Integer = 10 9Private Const giLayerMax As Integer = 3 10' *********************************************** 11' 開始 12' *********************************************** 13Private Sub Test_Sample_Miniature() 14 Dim iX As Integer 15 Range("A:A").Clear 16 lRow = 0 17 lCol = 1 18 For iX = 1 To giLayerMax 19 giLayer = 0 20 giWorkLayerMax = iX 21 lRow = lRow + 1 22 Cells(lRow, lCol) = "(r = " & iX & ")" 23 Call 自己参照(0, "") 24 Next 25End Sub 26' *********************************************** 27' 自己参照 28' *********************************************** 29Private Function 自己参照(iLayer As Integer, strPara As String) As Boolean 30 Dim iX As Integer 31 Dim intWorkLay As String 32 Dim strWorkPar As String 33 giLayer = giLayer + 1 34 intWorkLay = giLayer 35 strWorkPar = strPara 36 For iX = 0 To giCountMax 37 If giLayer < giWorkLayerMax And iX <> giCountMax Then 38 If strWorkPar = "" Then strPara = iX + 1 Else strPara = strWorkPar & "+" & iX + 1 39 Call 自己参照(iLayer, strPara) 40 giLayer = giLayer - 1 41 Else 42 If iX <> giCountMax Then 43 lRow = lRow + 1 44 strPara = strWorkPar & "+" & iX + 1 45 Cells(lRow, lCol) = strPara 46 End If 47 End If 48 Next 49End Function

(再追記)

VBA

1Option Explicit 2'変数域 3Private lRow As Long 4Private lCol As Long 5Private gintLayer As Integer 6'定数域 7Private Const giCountMax As Integer = 10 8Private Const giLayerMax As Integer = 3 9' *********************************************** 10' 開始 11' *********************************************** 12Private Sub Test_Sample_Miniature() 13 Dim iX As Integer 14 Range("A:A").Clear: lRow = 0: lCol = 1 15 For iX = 1 To giLayerMax 16 gintLayer = iX 17 lRow = lRow + 1: Cells(lRow, lCol) = "(r = " & iX & ")" 18 Call 自己参照(1, 1, "") 19 Next 20End Sub 21' *********************************************** 22' 自己参照 23' *********************************************** 24Private Function 自己参照(iPLayer As Integer, iPNextCount As Integer, strParam As String) As Boolean 25 Dim iX As Integer 26 Dim iY As Integer 27 Dim MyStr As String 28 For iX = iPNextCount To giCountMax 29 If iPLayer < gintLayer Then 30 If giCountMax > iX Then 31 Call 自己参照(iPLayer + 1, iX + 1, strParam & "+" & iX) 32 End If 33 Else 34 MyStr = strParam & "+" & iX 35 lRow = lRow + 1 36 Cells(lRow, lCol) = Mid(MyStr, 2) 37 End If 38 Next 39End Function

投稿2020/07/30 01:05

編集2020/08/04 05:30
tosi

総合スコア553

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

あー、なるほど、依頼の内容の意味を理解しました。

これをVBAで実現するには、かなりの高スペックマシンが要求されます。
この手のアルゴリズムは、一般的に、回帰処理をする為です。
度重なる回帰処理をすると、メモリを多く使用する為、スタック領域不足のエラーが発生します。

VBAのプログラミングで、一番の苦しいのは、動的配列が、プロシージャ外で使えない点や、ポインタ等の技が使えない点です。そのために、メモリ不足やスタック領域不足が発生しやすくなるのです。

他のプログラミング言語では、ポインタ等が使えるので、スタック領域不足になりにくいです。
私が考えたアルゴリズムでは、合計数が9で、スタック領域が不足してしまいました。

VBAは、基本的にマクロ言語の為、ExcelやWordを操作する為の道具で、計算処理する為には向きません。
VBAではなく、本格的なプログラム言語で実装されると、実現が可能かもしれません。
PythonやCなど。

私の意見では、VBAで実装することは、諦めた方が得策です。

でも、何かの参考になるかもしれませんので、ソースコードを入れておきます。

VBA

1Option Explicit 2 3Public p As Integer 4Public n As Integer 5 6Public Sub sample1() 7 Dim i As Integer 8 Dim a 9 10 n = InputBox("求める合計数 n の入力 (整数)") 11 p = InputBox("数値の個数 p の入力(整数)") 12 13 ReDim c(1 To p) As Integer 14 15 For i = 1 To p - 1 16 c(i) = 1 17 Next i 18 c(p) = n - i + 1 19 20 Call combi(c) 21 22End Sub 23 24Private Sub combi(c) 25 Dim ret As String 26 Dim i As Integer 27 Dim j As Integer 28 Dim a As Integer 29 30 31 If c(1) > Int(n / p) Then 32 Exit Sub 33 Else 34 If ck(c) Then 35 ret = "" 36 For i = 1 To p 37 ret = ret & c(i) & "+" 38 Next i 39 ret = Left(ret, Len(ret) - 1) 40 41 Debug.Print n & "C" & p & " = " & ret 42 43 End If 44 45 c(p) = c(p) - 1 46 If c(p) > 1 Then 47 a = 0 48 For i = (p - 1) To 1 Step -1 49 If c(i) <= (n - p) Then 50 c(i) = c(i) + 1 51 Else 52 c(i) = 1 53 End If 54 Call combi(c) 55 Next i 56 Else 57 c(p) = n - p 58 End If 59 60 End If 61End Sub 62 63Private Function ck(c) As Boolean 64 Dim i As Integer 65 Dim a As Integer 66 a = 0 67 For i = 1 To p 68 a = a + c(i) 69 Next i 70 If a = n Then 71 ck = True 72 Else 73 ck = False 74 End If 75End Function 76

投稿2020/07/29 14:39

編集2020/07/29 14:49
kai_keitai

総合スコア344

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問