|
くんくん さん、ちゃっぴさん、こんばんは。
>説明の付け足しです。
>日々、大幅に沢山の小幅を残幅が最小になる組み合わせを
>考えています。
>
>小幅は、前にも書いたとおりに、5刻みです。
>500という大幅があれば、
>小幅は、ランダムにあって、
>305
>305
>125
>300
>50
>430
>430
>といった具合です。
>その与えられた小幅の中のみで、組み合わせを考え、
>残幅の少ないものから順に表示させたいです。
>データ量は、すごく多いという量ではありません。
>
>結果は、こんな感じにしたいです。
>430 50 (残20)
>305 125 (残70)
>430 (残70)
>305 (残195)
>300 (残200)
>これで、すべての小幅が組み合わされています。
まず、仕様です。
上の例題に値を固定してコードを書きました。
コードを見ていただければ、変更は可能かと思います。
アクティブシートのセルA1〜A7に小幅メンバーの数値が入力して下さい。
A
1 305
2 305
3 125
4 300
5 50
6 430
7 430
この数値を入力して(値は変えてもかまいません)下記に記述してあるmainを実行して下さい。
C列 3行目からリストが表示され、F列には、差幅値(残幅)が表示されます。
では、コードです。
標準モジュール(Module1)に、
'====================================================================
Sub main()
Const 抜き取り = 2
Dim rng As Range
Dim 最小差幅リスト
Dim r_cnt As Long
Dim dsprow As Long
Dim nrng As Range
Dim 組み合わせ数 As Long
組み合わせ数 = 抜き取り
dsprow = 3
Set rng = Range("a1:a7") '小幅メンバセル範囲のセット
Do While Not rng Is Nothing
If rng.Count >= 抜き取り Then
組み合わせ数 = 抜き取り
Else
組み合わせ数 = rng.Count
End If
If get_min_comb(rng, 最小差幅リスト, 組み合わせ数, 500) = 0 Then
' ↑大幅の値を変更するならこの500を変更
wk = UBound(最小差幅リスト) - LBound(最小差幅リスト)
Range(Cells(dsprow, 3), Cells(dsprow, 3 + wk)).Value = 最小差幅リスト
Cells(dsprow, 6).Value = Evaluate("500-(" & Join(最小差幅リスト, "+") & ")")
dsprow = dsprow + 1
End If
Set rng = get_next_rng(rng, 最小差幅リスト)
' ↑表示したセル以外の範囲を設定
Loop
End Sub
'======================================================================
Function get_next_rng(rng, dellist) As Range
'指定されたセル範囲から、dellistに該当しないセルをひとつ削除する
ReDim rrng(1 To (UBound(dellist) - LBound(dellist) + 1)) As Range
For idx = LBound(dellist) To UBound(dellist)
Set rrng(idx) = Nothing
f_flg = 0
For Each crng In rng
If f_flg = 0 And crng.Value = dellist(idx) Then
f_flg = 1
Else
If Not rrng(idx) Is Nothing Then
Set rrng(idx) = Union(rrng(idx), crng)
Else
Set rrng(idx) = crng
End If
End If
Next
Next
Set get_next_rng = Nothing
For idx = LBound(rrng()) To UBound(rrng())
If Not rrng(idx) Is Nothing Then
If Not get_next_rng Is Nothing Then
Set get_next_rng = Application.Intersect(get_next_rng, rrng(idx))
Else
Set get_next_rng = rrng(idx)
End If
End If
Next idx
End Function
'=========================================================================
Function get_min_comb(rng As Range, myarray As Variant, 最大抜き取り数 As Long, 大幅 As Long) As Long
'指定されたセル範囲の組み合わせから大幅との差幅の小さい組み合わせを取得する
Dim idx As Long
Dim comb_list()
Dim ans()
Dim 差幅 As Long
get_max_comb = 1
差幅 = 大幅
For idx = 最大抜き取り数 To 1 Step -1
ReDim comb_list(1 To idx)
Call comb_init(rng, idx)
Do While get_comb(comb_list()) = 0
wk = Evaluate(大幅 & "-(" & Join(comb_list(), "+") & ")")
If Evaluate(大幅 & "-(" & Join(comb_list(), "+") & ")") >= 0 Then
If 差幅 > wk Then
差幅 = wk
Erase ans()
ans() = comb_list()
get_min_comb = 0
End If
End If
Loop
Next
If get_min_comb = 0 Then
myarray = ans()
End If
End Function
他の標準モジュール(Module2)に
'=======================================================================
Private c_svn As Long
Private c_myarray()
Private c_idx() As Long
Private cs_x() As Long
'=======================================================================
Function comb_init(rng As Range, seln As Long) As Double
'組み合わせ情報の初期化
c_svn = seln
Erase c_myarray
Erase c_idx
Erase cs_x()
i = 1
For Each crng In rng
ReDim Preserve c_myarray(1 To i)
c_myarray(i) = crng.Value
i = i + 1
Next
ReDim cs_x(1 To seln)
ReDim c_idx(1 To seln)
For i = 1 To UBound(c_idx())
cs_x(i) = i
c_idx(i) = i
Next
c_idx(UBound(c_idx())) = c_idx(UBound(c_idx())) - 1
comb_init = WorksheetFunction.Combin(rng.Count, seln)
End Function
'======================================================================
Function get_comb(ans()) As Long
'組み合わせメンバーの取得
get_comb = 1
For i = UBound(c_idx()) To LBound(c_idx()) Step -1
If c_idx(i) + 1 <= UBound(c_myarray()) - c_svn + i Then
c_idx(i) = c_idx(i) + 1
get_comb = 0
Exit For
Else
c_idx(i) = cs_x(i) + 1
cs_x(i) = cs_x(i) + 1
For j = i + 1 To UBound(cs_x())
cs_x(j) = cs_x(j - 1) + 1
c_idx(j) = cs_x(j)
Next j
End If
Next
If get_comb = 0 Then
For i = LBound(c_idx()) To UBound(c_idx())
ans(i) = c_myarray(c_idx(i))
Next
End If
End Function
以上です。
くんくん さんが都合の良いような変更は、mainプロシジャーの入力データの箇所の
変更でよいと思いますが・・・。
確認してみて下さい。
それから、次回からは、こういうアルゴリズムに関するようなご質問は
もう少し詳しく(例えば、例も最低3例ぐらい)記述して下さいね!!
|
|