Question: There is an ordered array of integer elements and a limit. It is necessary to find the minimum possible and maximum possible sum that can greater or equal the limit, for the given elements. The minimum sum is the minimum sum of the sequence greater or equal than limit The maximum sum, is the sum of the sequence that satisfies the conditions, and gives the largest result Conditions:  The elements of the sequence can be repeated: for example you can take 101 + 101 + 101 + 101 + 101 + 201 + 201 When summing, you can not skip elements of the array, for example, you can not add 101 + 301 at once, must be 101 + 201 + 301 Stop summing as soon as you reach the limit  First Example:  arr = [100, 200, 300, 1000] limit = 1000 The minimum here is 1000, because we can take 10 times 100 for example. The maximum here is 1900, since we can take 100 + 200 + 300 + 300 + 1000.  Second Example:  arr = [3, 10, 15] limit = 1000 The minimum here is 1000, because we can take 300 times 3 and 10 times 10. The maximum here is 1014, since we can take 318 times 3 and 3 time 10 and 2 times 15  I wrote 1 algorithm based on recursion and one based on dynamic programming. Both the first and the second one produce incorrect results in certain situations Example for Python: from pprint import pprint from typing import Tuple, List import resource import sys resource.setrlimit(resource.RLIMIT_STACK, (0x10000000, resource.RLIM_INFINITY)) sys.setrecursionlimit(0x100000) class CollectingRangeAnalyzer: def __init__(self): self.memo = {} def recursion_method(self, pools: List[int], target_cap: int) -> Tuple[float, float]: self._collect_helper(pools, target_cap, [], 0) if not self.memo: raise ValueError("No valid range found") max_cap = max(self.memo) min_cap = min(self.memo, key=lambda x: x if x >= target_cap else float("inf")) return max_cap, min_cap def _collect_helper(self, pools_, target_sum_, path, cur_sum): if cur_sum >= target_sum_: return if self.memo.get(cur_sum): return for i, v in enumerate(pools_): cur_sum += v path.append(v) self._collect_helper(pools_, target_sum_, path, cur_sum) self.memo[cur_sum] = True cur_sum -= v path.pop() @staticmethod def dynamic_method(arr, limit): table = [] arr_size = len(arr) n_cols = limit // arr[0] + 1 max_cap = float("-inf") min_cap = float("inf") for i in range(arr_size): table.append([]) for j in range(n_cols): table[i].append(0) for i in range(arr_size): for j in range(n_cols): if i == 0 and arr[0] * (j + 1) <= limit + arr[i]: table[i][j] = arr[i] * (j + 1) elif i > j or j < 0: table[i][j] = table[i - 1][j] else: diagonal_prev = table[i - 1][j - 1] j_prev = table[i][j-1] if diagonal_prev < limit: table[i][j] = diagonal_prev + arr[i] else: table[i][j] = max(diagonal_prev, j_prev) max_cap = max(table[i][j], max_cap) min_cap = min(table[i][j], min_cap, key=lambda x: x if x >= limit else float("inf")) return max_cap, min_cap # First Example first_analysis_class = CollectingRangeAnalyzer() first_array = [100, 200, 300, 1000] first_limit = 1000 rec_first = first_analysis_class.recursion_method(first_array, first_limit) # output: (1900, 1000) SUCCESS dynamic_first = first_analysis_class.dynamic_method(first_array, first_limit) # output: (1900, 1000) SUCCESS # But if added the 10000 in first_array and run again I'll get the wrong result in the recursion function. # # first_array = [100, 200, 300, 1000, 10000] # # # rec_first = first_analysis_class.recursion_method(first_array, first_limit) # output: (10900, 1000) WRONG # dynamic_first = first_analysis_class.dynamic_method(first_array, first_limit) # output: (1900, 1000) SUCCESS # Second Example second_analysis_class = CollectingRangeAnalyzer() second_array = [3, 10, 15] second_limit = 1000 rec_second = second_analysis_class.recursion_method(second_array, second_limit) # output: (1014, 1000) SUCCESS dynamic_second = second_analysis_class.dynamic_method(second_array, second_limit) # output: (1012, 1000) WRONG 

Answer: I assume that you need to always start at the beginning of your sequence. Your examples were still not clear on that. If that is true then this should work: import heapq def min_max_limit_sum (arr, limit): # A path will be (idx_k, ...(idx_1, (idx_0, None))...) # By (value, index): path known = {} # heap of (value, counter, (next_index, prev_path)) upcoming = [(0, 0, (0, None))] counter = 1 best_min = limit + sum(arr) min_path = None best_max = limit - 1 max_path = None # While there is stuff in the heap. while len(upcoming): value, _, next_path = heapq.heappop(upcoming) i = next_path[0] if (value, i) in known or len(arr) <= i: # Filter out alternate routes, and running off the end of the sequence. continue else: path = next_path[1] known[(value, i)] = path if value < limit: value += arr[i] heapq.heappush(upcoming, (value, counter, (i, next_path))) heapq.heappush(upcoming, (value, counter, (i+1, next_path))) counter += 1 else: if value < best_min: best_min = value min_path = path if best_max < value: best_max = value max_path = path return (best_min, min_path, best_max, max_path) print(min_max_limit_sum([100, 200, 300, 1000], 1000))  If the assumption is not true, just set upcoming to have an entry for every single index.