Мое решение очень похоже на Davids.
Успение: набор чисел упорядочен по возрастанию.
Вызвать функцию и начать с самого высокого числа, передать пустое частичное решение и попытаться рассчитать все возможные суммы набора чисел, которые возвращают общее количество. Суммы возвращаются как Коллекция.
Функция:
- создать список, чтобы держать все решения
- испытаний для каждого числа в наборе (начиная с пройденным
numberSetIndex
и двигаться вниз):
- если
number > total
затем перейти к следующее число
- добавьте номер в пар. решение
- if
number = total
затем добавьте это парное решение к список и перейти к следующему номеру
- если
number < total
затем
- вызвать эту функцию снова (с
total -= number
и копией частичного решения, и с текущим индексом числа)
- дописывания всех возвращенных решений
- вернуть все решения
Остерегайтесь: Я не понял, хотите ли вы использовать каждый номер набора только один раз для суммы, поэтому приведенный ниже код также рассчитает суммы, содержащие более одного экземпляра числа в данном наборе.
Если вы хотите, чтобы каждый номер появляться только один раз, найдите строку
Set result = AllSumsForTotalFromSet(total - number, numberSet, index, CopyAndReDimPlus1(partialSolution))
в функции Function AllSumsForTotalFromSet
и заменить index
с index-1
в рекурсивном вызове.
Sub Test_AllSumsForTotalFromSet()
Dim numberSet, total As Long, result As Collection
numberSet = Array(65536, 131072, 262144, 524288, 104576, 2097152)
total = 366720
Set result = GetAllSumsForTotalFromSet(total, numberSet)
Debug.Print "Possible sums: " & result.count
PrintResult result
End Sub
Function GetAllSumsForTotalFromSet(total As Long, ByRef numberSet As Variant) As Collection
Set GetAllSumsForTotalFromSet = New Collection
Dim partialSolution(1 To 1) As Long
Set GetAllSumsForTotalFromSet = AllSumsForTotalFromSet(total, numberSet, UBound(numberSet), partialSolution)
End Function
Function AllSumsForTotalFromSet(total As Long, ByRef numberSet As Variant, numberSetIndex As Long, ByRef partialSolution() As Long) As Collection
Dim index As Long, number As Long, result As Collection
Set AllSumsForTotalFromSet = New Collection
'break if numberSetIndex is too small
If numberSetIndex < LBound(numberSet) Then Exit Function
For index = numberSetIndex To LBound(numberSet) Step -1
number = numberSet(index)
If number <= total Then
'append the number to the partial solution
partialSolution(UBound(partialSolution)) = number
If number = total Then
AllSumsForTotalFromSet.Add partialSolution
Else
Set result = AllSumsForTotalFromSet(total - number, numberSet, index, CopyAndReDimPlus1(partialSolution))
AppendCollection AllSumsForTotalFromSet, result
End If
End If
Next index
End Function
'copy the passed array and increase the copy's size by 1
Function CopyAndReDimPlus1(ByVal sourceArray As Variant) As Long()
Dim i As Long, destArray() As Long
ReDim destArray(LBound(sourceArray) To UBound(sourceArray) + 1)
For i = LBound(sourceArray) To UBound(sourceArray)
destArray(i) = sourceArray(i)
Next i
CopyAndReDimPlus1 = destArray
End Function
'append sourceCollection to destCollection
Sub AppendCollection(ByRef destCollection As Collection, ByRef sourceCollection As Collection)
Dim e
For Each e In sourceCollection
destCollection.Add e
Next e
End Sub
Sub PrintResult(ByRef result As Collection)
Dim r, a
For Each r In result
For Each a In r
Debug.Print a;
Next
Debug.Print
Next
End Sub
Вы можете использовать динамическое программирование: тест все одночленные суммы, если общий не найдено, добавьте 2 два терминов суммы и т.д. Для того, чтобы свести к минимуму накладные использовать обрезку: если п-Турм сумма gtreater, чем общие есть нет необходимости в тестировании n + 1-turms на основе этой суммы. –