Split the N<=40 array into two halves A and B (sizes ~N/2). Enumerate all subset sums of each half (2^(N/2) each) via recursion or bitmask; sort one list (say sumsB). For every sum a in sumsA, binary-search in sumsB for value closest to (T - a) to get best combined sum close to T. Track best absolute difference and subset if you need the actual elements.python
from bisect import bisect_left
def subset_sums(arr):
sums = [(0, [])] # (sum, indices)
for i, v in enumerate(arr):
new = [(s+v, idx+[i]) for s, idx in sums]
sums += new
return sums
def closest_subset(arr, T):
n = len(arr)
A, B = arr[:n//2], arr[n//2:]
sumsA = subset_sums(A) # O(2^(N/2))
sumsB = subset_sums(B)
sumsB.sort(key=lambda x: x[0])
valsB = [s for s, _ in sumsB]
best = None # (absdiff, total_sum, indices)
for sa, idxA in sumsA:
want = T - sa
i = bisect_left(valsB, want)
for j in (i-1, i):
if 0 <= j < len(valsB):
sb, idxB = sumsB[j]
total = sa + sb
diff = abs(T - total)
if best is None or diff < best[0]:
# convert B indices to global indices
b_offset = n//2
best = (diff, total, idxA + [b_offset + ii for ii in idxB])
if diff == 0:
return best[1], best[2]
return best[1], best[2]
# Example
# total, indices = closest_subset([3, -2, 7, 1, 4], 6)
Key points:- Splitting reduces exponent from 2^N to ~2*2^(N/2).- Sorting sumsB enables O(log 2^(N/2)) = O(N/2) lookup per sumsA entry.Time complexity: O(2^(N/2) * (N/2)) for enumeration + O(2^(N/2) log 2^(N/2)) for sorting + O(2^(N/2) log 2^(N/2)) for searches → overall O(2^(N/2) * N). Space: O(2^(N/2)) to store half-sums.Edge cases:- N small (fall back to brute force if desired)- Many duplicates — still works- Need actual elements: track indices as aboveAlternatives:- Use meet-in-the-middle with pruning (keep only Pareto-optimal sums) or use hash-based near neighbor for faster approximate lookups.