1

Given a set of positive integers, and a target sum k, find the subset that sums to exactly k or least exceeds k. (i.e. equal or minimal overshoot)

This problem is occurring in a real life business feature-request, and the set size is expected to usually range from 1 to 30. It has to be solvable by low-end-PCs within say 3 seconds, so I guesstimate that a bruteforce method probably couldn't handle much more than 10 input integers?

I've looked thru search hits related to subset sum and knapsack, but have not seen anyone discuss this >= variation yet.

Doochz
  • 1,039
  • 2
  • 14
  • 25
  • It is rather easy to implement that variation, given you understand how the dynamic programming approach works. – Willem Van Onsem Aug 16 '19 at 14:41
  • 1
    See for example an answer on the *closest* subset https://stackoverflow.com/q/34188694/67579 . Yes the above accepts both overshooting and undershooting, but the idea is the same. – Willem Van Onsem Aug 16 '19 at 14:42

1 Answers1

1

This is a rather simple extension of the original program: we simply use the dynamic programming algorithm, but also store lists we generate if these are overshooting the original value.

We can for example implement such algorithm as:

def least_gt_subset_sum(items, k):
    vals = [None]*(k+1)
    vals[0] = ()
    best_v = None
    best_k = 0
    for item in items:
        for i in range(k-1, -1, -1):
            if vals[i] is not None:
                if i + item <= k and vals[i+item] is None:
                    vals[i+item] = (*vals[i], item)
                if i + item > k and (best_v is None or i + item < best_v):
                    best_v = i + item
                    best_k = (*vals[i], item)
    if vals[k] is not None:
        return vals[k]
    else:
        return best_k

So here we use the same trick, but in case the value is higher than k, we do some bookkeeping, and store the best result. At the end, we look if there is a value that matches exactly, if not, we return the best set that was higher, otherwise we return the one that was exact.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555