下面是我用來查找總數達到某個值的組合的代碼。
我把它迷上這部長達一個窗體,所以只是手動提供值:
MaxSoln =被發現
最大的解決方案
TargetVal =需要合計到
值SearchRange =您的值存儲在Excel中的範圍
Option Explicit
Function RealEqual(A, B, Optional Epsilon As Double = 0.00000001)
RealEqual = Abs(A - B) <= Epsilon
End Function
Function ExtendRslt(CurrRslt, NewVal, Separator)
If CurrRslt = "" Then ExtendRslt = NewVal _
Else ExtendRslt = CurrRslt & Separator & NewVal
End Function
Sub recursiveMatch(ByVal MaxSoln As Long, ByVal TargetVal, InArr(), _
ByVal HaveRandomNegatives As Boolean, _
ByVal CurrIdx As Long, _
ByVal CurrTotal, ByVal Epsilon As Double, _
ByRef Rslt(), ByVal CurrRslt As String, ByVal Separator As String)
On Error Resume Next
Dim i As Long
For i = CurrIdx To UBound(InArr)
If RealEqual(CurrTotal + InArr(i), TargetVal, Epsilon) Then
Rslt(UBound(Rslt)) = ("Totaled to: " & CombinationFinder.TotalTo.Value) _
& Separator & ExtendRslt(CurrRslt, InArr(i), Separator)
If MaxSoln = 0 Then
Else
If UBound(Rslt) >= MaxSoln Then Exit Sub
End If
ReDim Preserve Rslt(UBound(Rslt) + 1)
ElseIf IIf(HaveRandomNegatives, False, CurrTotal + InArr(i) > TargetVal + Epsilon) Then
ElseIf CurrIdx < UBound(InArr) Then
recursiveMatch MaxSoln, TargetVal, InArr(), HaveRandomNegatives, _
i + 1, _
CurrTotal + InArr(i), Epsilon, Rslt(), _
ExtendRslt(CurrRslt, InArr(i), Separator), _
Separator
If MaxSoln <> 0 Then If UBound(Rslt) >= MaxSoln Then Exit Sub
Else
'we've run out of possible elements and we _
still don't have a match
End If
Next i
End Sub
Function ArrLen(Arr()) As Long
On Error Resume Next
ArrLen = UBound(Arr) - LBound(Arr) + 1
End Function
Function checkRandomNegatives(Arr) As Boolean
Dim i As Long
i = LBound(Arr)
Do While Arr(i) < 0 And i < UBound(Arr): i = i + 1: Loop
If i = UBound(Arr) Then Exit Function
Do While Arr(i) >= 0 And i < UBound(Arr): i = i + 1: Loop
checkRandomNegatives = Arr(i) < 0
End Function
Sub startSearch()
'The selection should be a single contiguous range in a single column. _
The first cell indicates the number of solutions wanted. Specify zero for all. _
The 2nd cell is the target value. _
The rest of the cells are the values available for matching. _
The output is in the column adjacent to the one containing the input data.
Dim searchrange As Range
Set searchrange = Range(CombinationFinder.RefRange)
If Not TypeOf searchrange Is Range Then GoTo ErrXIT
If searchrange.Areas.Count > 1 Or searchrange.Columns.Count > 1 Then GoTo ErrXIT
If searchrange.Rows.Count < 3 Then GoTo ErrXIT
Dim TargetVal, Rslt(), InArr(), StartTime As Date, MaxSoln As Long, _
HaveRandomNegatives As Boolean
MaxSoln = CombinationFinder.Max.Value
TargetVal = CombinationFinder.TotalTo.Value
InArr = Application.WorksheetFunction.Transpose(searchrange)
HaveRandomNegatives = checkRandomNegatives(InArr)
If Not HaveRandomNegatives Then
ElseIf MsgBox("At least 1 negative number is present between positive numbers" _
& vbNewLine _
& "It may take a lot longer to search for matches." & vbNewLine _
& "OK to continue else Cancel", vbOKCancel) = vbCancel Then
Exit Sub
End If
ReDim Rslt(0)
recursiveMatch MaxSoln, TargetVal, InArr, HaveRandomNegatives, LBound(InArr), 0, 0.00000001, Rslt, "", ", "
ActiveSheet.Range("A1:A" & ArrLen(Rslt)) = Application.WorksheetFunction.Transpose(Rslt)
Exit Sub
ErrXIT:
MsgBox "Please select cells in a single column before using this macro" & vbNewLine _
& "The selection should be a single contiguous range in a single column." & vbNewLine _
& "The first cell indicates the number of solutions wanted. Specify zero for all." & vbNewLine _
& "The 2nd cell is the target value." & vbNewLine _
& "The rest of the cells are the values available for matching." & vbNewLine _
& "The output is in the column adjacent to the one containing the input data."
End Sub
根據其值對您的原始列表按降序排序。然後只要總數小於指定總數,繼續挑選物品。 –
@NalinAgrawal你會介意給我看我如何編碼。我很討厭VB代碼 –