[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『複数の値からある合計数に一致する組み合わせ』(シン)
500という合計値があり、現在20通りぐらいのランダムな値のなかで何れかの組み合わせで合計500になる組み合わせをもとめたい。
新規ブックにて試してください。
標準モジュール(Module1)に
'================================================================= Option Explicit Private svarray() As Variant Private ccomb As Long '================================================================= Sub open_comb(myarray As Variant) '組合せ処理のオ−プン 'myarray 組合せを行う配列 Dim ele As Variant Dim g0 As Long g0 = 0 Erase svarray() For Each ele In myarray ReDim Preserve svarray(1 To g0 + 1) svarray(g0 + 1) = ele g0 = g0 + 1 Next ccomb = 0 End Sub '================================================================= Function get_comb(Optional flg As Long = 0) As Variant '組合せリストを取り出す 'flg 0 次のデータ 1 桁スキップ 'get_comb 組合せの配列 Falseは、データの終わり Dim g0 As Long Dim g1 As Long Dim ret As Boolean Dim ans() As Variant Dim oncnt As Long ret = False If flg = 0 Then ccomb = ccomb + 1 If ccomb < (2 ^ UBound(svarray())) Then ret = True End If ElseIf flg = 1 Then oncnt = 0 For g0 = 0 To UBound(svarray()) - 1 If ccomb And 2 ^ g0 Then oncnt = oncnt + 1 ccomb = ccomb And (Not 2 ^ g0) Else If oncnt >= 2 Then ccomb = ccomb Or 2 ^ g0 ret = True Exit For End If End If Next End If If ret = True Then g1 = 0 For g0 = 0 To UBound(svarray()) - 1 If ccomb And 2 ^ g0 Then ReDim Preserve ans(1 To g1 + 1) ans(g1 + 1) = svarray(g0 + 1) g1 = g1 + 1 End If Next get_comb = ans() Erase ans() Else get_comb = False End If End Function '================================================================= Sub close_comb() '組合せ処理のクローズ Erase svarray() ccomb = 0 End Sub
別の標準モジュール(Module2)に
'================================================================= Sub sample1() Dim fit As Variant Dim rw As Long Dim mem As Variant Dim flg As Long Dim rng As Range Set rng = Range("a1:a20") With rng .Formula = "=int(rand()*300)+1" .Value = .Value .Sort Key1:=Range("A1"), Order1:=xlAscending, Header:=xlGuess, _ OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, SortMethod _ :=xlPinYin, DataOption1:=xlSortNormal End With DoEvents Range("e:e").Clear fit = Application.InputBox("合計値を入力して", , , , , , , 2) If TypeName(fit) <> "Boolean" Then Call open_comb(rng.Value) flg = 0 mem = get_comb(flg) Do Until TypeName(mem) = "Boolean" flg = 0 If Application.Sum(mem) = Val(fit) Then Cells(rw + 1, 5).Value = Join(mem, "\") rw = rw + 1 ElseIf Application.Sum(mem) > Val(fit) Then flg = 1 End If mem = get_comb(flg) Loop Call close_comb End If Set rng = Nothing End Sub としてSample1を実行してください。
A1:A20にランダムな数値が表示されます。 求める合計値を入力してください。 A1:A20の数値で、その合計値になる組合せをE列に表示します。 結果は、¥ 文字で区切られています。
試してみてください。
これでうまくいくようなら、ご自分の仕様に合わせて、 Module1を使って見みてください。標本数が30件までは使えます。
標本であるA1:A20は、昇順に整列されている必要があります
ichinose
とりあえず、頑張ってみます。
他掲示板ですが、参考になるかもしれません。 http://oshiete.goo.ne.jp/qa/5212312.html
他にもこの種の問題は過去に多くの相談例が ありますので検索されたらよいでしょう。
shibaraku
こんにちは よく質問に出るナップサック問題ですネ。ネットで調べるとよく分かるかと思います。 データ数20個の総組合せ数1,048,575、データ数30個の総組合せ数1,073,741,823となり、データ数を増やすと組合せ数は爆発的なかんじで増えます。
ナップサック問題をエクセルの機能で行うには、ソルバーを使用しますが、バージョン等によりデータ数の取扱数が変わります。 (PC本体のCPU及びソフトの性能向上等が関係すると思料します。) Windos XP Excel2003の場合データ数20個(総組合せ数1,048,575)で約40秒かかり、データ数21個 (総組合せ数2,097,151)では2分以上かかり、かつ、解が出ない場合がある。 Windos Vista Excel2007 ソルバーを使用して、下記の35個データで値を求めてみました データ数35個(総組合せ数34,359,738,367)で値「500」を求めた。約11秒程度 =A1+A6+A7+A8+A9+A15+A18+A23+A26+A28+A32 データ数35個(総組合せ数34,359,738,367)で値「400」を求めた。約9秒程度 =A6+A8+A9+A11+A13+A22+A23+A24+A27+A29+A35 データ数35個(総組合せ数34,359,738,367)で値「300」を求めた。約9秒程度 =A13+A14+A15+A17+A18+A23+A27+A28+A29+A35
(Windos 7 Excel2007は、Windos Vista Excel2007より1〜2秒程度早い感じ?)
A1〜A35までのデータです。(参考) 17 20 33 43 50 55 58 60 73 24 35 15 10 40 28 36 42 53 38 19 21 27 38 41 29 64 10 28 37 31 30 26 18 44 14
ソルバーを使用する方法 B列空白 C1セルに=SUMPRODUCT(A1:A35,B1:B35) 「ソルバー:パラメータ設定」ダイアログボックス 目的セル:「C1」 目標値:「値」にレ点を入れる、右側の枡に検索する値を入力。例では500なので枡に500と入力 変化させるセル:B1:B35 「制約条件」の「追加」ボタンをクリックする。「制約条件の追加」ダイアログボックスが表示される。 「制約条件の追加」ダイアログボックスの"セル参照"に「B1:B35」と入力 「制約条件の追加」ダイアログボックスに表示される"セル参照"のウィンドウの「<=」の記号の右の▼をクリックし、「データ」を選ぶ。 「制約条件の追加」ダイアログボックスの"制約条件"に、「バイナリ」が自動的に入ります。 「追加」ボタンを押し、次に「キャンセル」ボタンを押します。 「ソルバー:パラメータ設定」ダイアログボックスの実行ボタンを押します。 参考に実施してみてください。XPでしたらデータ数は20個まででお願いします。
(atiboh)
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.