- ベストアンサー
数値の組み合わせを求める方法
数値の組み合わせを求めるのによい方法はありませんか。 具体例を書きますのでよろしくお願いします。 2,3,5,8の4個の数値があります。 この数値のいずれかを足して10になる組み合わせを 求めたい。 この場合の答えは、 2+3+5=10または2+8=10から、 2,3,5の組み合わせ、または2,8の組み合わせ となります。 また、上の場合で、足して11になる数値の組み合わ せは、3,8の組み合わせのみです。 これらは、簡単に求められますが、数値が多くなって くると手で計算していては、ものすごく時間がかかって しまいます。 エクセルを使って、ササーッと求める方法があったら 教えてください。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
プログラムの書き方は、あまり自信ないですけど、 一例として作って見ました。 VBAが分かる様なので、考え方が分かれば私の作り方より きれいな書き方が出来るのではないかと思います。 標準モジュールに下記のプログラムを貼り付けて [Sheet1]のA列に数値を入力し、 B1セルに求めたい数値を入力し Testを実行してください [Sheet1]のC列,D列・・・に該当する組み合わせを表示します。 Sub test() Dim ws As Worksheet Dim tbl As Variant Dim ans As Long Set ws = Worksheets("Sheet1") '対象となる数値群 tbl = ws.Range(ws.Range("A1"), ws.Cells(ws.Rows.Count, "A").End(xlUp)).Value '求める数値 ans = ws.Range("B1") '表示位置クリア ws.Range("C:Z").Clear MsgBox Anser(1, 0, ws, 1, 3, tbl, ans) & "個の組み合わせがありました" End Sub 'srow:検索を始める行 , wtotal:現在の合計 'ws:表示するシート,wrow:表示する行 , wcolumn:表示する列 'wtbl:対象となる数値群 , wans:求める数値 '戻り値:組み合わせの個数 Function Anser(ByVal srow As Long, ByVal wtotal As Long, ByVal ws As Worksheet, ByVal wrow As Long, ByVal wcolumn As Integer, ByVal wtbl As Variant, ByVal wans As Long) As Long Dim i As Long Dim wcnt As Long Dim wtl As Long Anser = 0 For i = srow To UBound(wtbl, 1) wtl = wtotal + wtbl(i, 1) If (wtl = wans) Then '求める数値と同じ ws.Cells(wrow, wcolumn) = wtbl(i, 1) Anser = Anser + 1 wrow = wrow + 1 ElseIf (wtl < wans) Then '求める数値より少ない wcnt = Anser(i + 1, wtl, ws, wrow, wcolumn + 1, wtbl, wans) If (wcnt > 0) Then '求める数値になる組み合わせがある For j = 1 To wcnt ws.Cells(wrow, wcolumn) = wtbl(i, 1) wrow = wrow + 1 Next j Anser = Anser + wcnt End If 'Else 'ソートされている場合コメントをはずす ' Exit For'ソートされている場合コメントをはずす End If Next i End Function A列の数値がソートされていれば、最後のコメント(')をはずしてください わからなければ、補足してください。 (テストを少数データでしか試してませんので、 バグがあったらそちらも補足してください)
その他の回答 (3)
- nishi6
- ベストアンサー率67% (869/1280)
2、3、5、8の場合の例です。 B1、C1、D1、E1に使用する数 2、3、5、8を入力します。 F1に指定する数値を入力します。 数値の組み合わせの種類は=2^4-1=15 なので A2~A16に1から15の数値を入力します。(2^4の4は使う数字の個数です) B2に =INT(A2/2^3) C2に =INT(MOD(A2,2^3)/2^2) D2に =INT(MOD(A2,2^2)/2^1) E2に =INT(MOD(A2,2^1)/2^0) F2に =IF(SUMPRODUCT($B$1:$E$1,B2:E2)=F$1,"OK","") とします。3行目から16行目にこれをコピーします。 │ A│ B C D E│ F ──┼──┼───────────┼──── 1│ │ 2 3 5 8│10 2│ 1│ 0 0 0 1│ 3│ 2│ 0 0 1 0│ 4│ 3│ 0 0 1 1│ 5│ 4│ 0 1 0 0│ 6│ 5│ 0 1 0 1│ 7│ 6│ 0 1 1 0│ 8│ 7│ 0 1 1 1│ 9│ 8│ 1 0 0 0│ 10│ 9│ 1 0 0 1│OK 11│10│ 1 0 1 0│ 12│11│ 1 0 1 1│ 13│12│ 1 1 0 0│ 14│13│ 1 1 0 1│ 15│14│ 1 1 1 0│OK 16│15│ 1 1 1 1│ 一致する組合せがあればF列に『OK』がでます。 組合せパターンを2進数で表し、掛算して合計を求めています。 3個の数値の場合もすぐできるでしょう。 同じ理屈で、ユーザー定義関数を作れば、単純な繰り返し演算で計算できることになります。 VBAの場合、ビット演算ができるので単純になります。 また、アドインのDEC2BIN関数を使えば、2進数文字列を作ることができます。 アドイン関数を組み込んでいないので上のような方法にしてみました。 ご参考に。
お礼
ありがとうございます。 なんといえばいいのか、逆転の発想というのか、脳味噌が洗われる思いです。 同じ理屈で、・・・以下の文はちょっと私にはむずかしすぎです。。もっと勉強します。
- taisuke555
- ベストアンサー率55% (132/236)
EXCELの関数での方法は、まったく思いつきません。 VBAなら全ての組み合わせを調べれば、できると思います。 必要であれば、補足してください。 VBAのプログラムを作ってみます。(書き方にはあまり自信がありませんが・・・) (VBAが良く分からなければ、修正が難しいと思いますので、その場合は、 数値:Sheet1のA列で個数は未定、ソートされている 求める数値:Sheet1のB1セル 組み合わせの表示位置:Sheet1のC列以降 のように具体的に補足してください)
お礼
いやー、作ってくださるのですか。お世話になります。 VBAは、そこそこ書けるつもりですが、わからないときには、教えてください。
- nemaro
- ベストアンサー率28% (40/139)
数学は苦手ですが参考になればうれしい。
お礼
ありがとうございます。やはり、すべての組み合わせをやってみないとだめみたいですね。うーん。
お礼
taisuke555さんのVBA動かしてみました。 たちまち、答えが出て感動ものです。 プログラムの内容は、合計値と数値のセル範囲を取得して、セル範囲の数値を順番に足していって、合計値と合うたびに、表示位置もずらして、でもって組み合わせの個数もカウントしていくということのようですが、それをプログラムしてしまうところが、凄いです。私などとてもとてもできそうにありません。でもいつかはという気持ちです。本当にどうもありがとうございました。
補足
早速ありがとうございます。 私のVBA力は、事務処理中心で手作業での反復の自動化が主なので、書いてくださったプログラムには目がくらみました。読んで、考えて、テストして、また、ご連絡します。それまで、すこし待ってください。