It is rather a hybrid solution with dynamic programming and backtracking. We can use Back Tracking only to solve this problem, but then we must do an exhaustive search (2 ^ N) to find a solution. The DP part optimizes the search space in reverse tracking.
import sys from collections import OrderedDict MinimumSum = 31 MaxArraySize = 4 InputData = sorted([1,4,5,10,17,34]) # Input part is over Target = MinimumSum + 1 Previous, Current = OrderedDict({0:0}), OrderedDict({0:0}) for Number in InputData: for CurrentNumber, Count in Previous.items(): if Number + CurrentNumber in Current: Current[Number + CurrentNumber] = min(Current[Number + CurrentNumber], Count + 1) else: Current[Number + CurrentNumber] = Count + 1 Previous = Current.copy() FoundSolution = False for Number, Count in Previous.items(): if (Number >= Target and Count < MaxArraySize): MaxArraySize = Count Target = Number FoundSolution = True break if not FoundSolution: print "Not possible" sys.exit(0) else: print Target, MaxArraySize FoundSolution = False Solution = [] def Backtrack(CurrentIndex, Sum, MaxArraySizeUsed): global FoundSolution if (MaxArraySizeUsed <= MaxArraySize and Sum == Target): FoundSolution = True return if (CurrentIndex == len(InputData) or MaxArraySizeUsed > MaxArraySize or Sum > Target): return for i in range(CurrentIndex, len(InputData)): Backtrack(i + 1, Sum, MaxArraySizeUsed) if (FoundSolution): return Backtrack(i + 1, Sum + InputData[i], MaxArraySizeUsed + 1) if (FoundSolution): Solution.append(InputData[i]) return Backtrack(0, 0, 0) print sorted(Solution)
Note. . In accordance with the examples you specified in the question, the minimum amount and maximum size of the array are strictly larger and smaller than the specified values, respectively.
For this entry
MinimumSum = 31 MaxArraySize = 4 InputData = sorted([1,4,5,10,17,34])
Exit
[5, 10, 17]
where as, for this entry
MinimumSum = 31 MaxArraySize = 3 InputData = sorted([1,4,5,10,17,34])
Exit
[34]
Explanation
Target = MinimumSum + 1 Previous, Current = OrderedDict({0:0}), OrderedDict({0:0}) for Number in InputData: for CurrentNumber, Count in Previous.items(): if Number + CurrentNumber in Current: Current[Number + CurrentNumber] = min(Current[Number + CurrentNumber], Count + 1) else: Current[Number + CurrentNumber] = Count + 1 Previous = Current.copy()
This part of the program finds the minimum number of numbers from the input data necessary so that the sum of numbers from 1 to the maximum possible number (which is the sum of all input data). This is a solution for dynamic programming, for a backpack problem. You can read about it online.
FoundSolution = False for Number, Count in Previous.items(): if (Number >= Target and Count < MaxArraySize): MaxArraySize = Count Target = Number FoundSolution = True break if not FoundSolution: print "Not possible" sys.exit(0) else: print Target, MaxArraySize
This part of the program finds a Target value that matches the MaxArraySize criteria.
def Backtrack(CurrentIndex, Sum, MaxArraySizeUsed): global FoundSolution if (MaxArraySizeUsed <= MaxArraySize and Sum == Target): FoundSolution = True return if (CurrentIndex == len(InputData) or MaxArraySizeUsed > MaxArraySize or Sum > Target): return for i in range(CurrentIndex, len(InputData)): Backtrack(i + 1, Sum, MaxArraySizeUsed) if (FoundSolution): return Backtrack(i + 1, Sum + InputData[i], MaxArraySizeUsed + 1) if (FoundSolution): Solution.append(InputData[i]) return Backtrack(0, 0, 0)
Now that we know that a solution exists, we want to recreate the solution. Here we use the backtracking technique. You can easily find many good lessons about this also on the Internet.