Reputation: 449
I have this variation of knapsack with very few constraints, and the lack of contraints does that i really don't know where to start.
Given a set S of positive integers. could be: 1 2 3 4 5 6 7 8 9 10 11 12 13
find two non-overlapping subsets that have the same total each. The two sets do not need to contain all numbers in S. So for the former example, the answer would be [1,2] and [3]
Usually these problems have constraints such as the subsets needing to have specific sums, or the subsets needing to span over all elements of S. This makes it hard for me to imagine how to solve this via bruteforce. Every time I come up with a dynamic programming table, I can't get it to cover all possible permutations of subsets
Upvotes: 2
Views: 164
Reputation: 80187
This problem might be solved like subset sum problem in pseudopolynomial time O(n*summ)
We fill array 0..summ
with possible subset sums, and when we meet the same sum - we stop.
Two equal sums might be composed with some equal items - and we just remove them, so the rest sums contain only distinct items.
Example in Python using binary arithmetics to store sets (bit i+1
corresponds to using i-th item in sum). common
contains equal bits, we remove them using xor operation.
The last lines retrieve needed sets themselves.
L = [2,5,11,17,29,37,43]
summ = sum(L)
A =[0]*(summ+1)
A[0] = 1
X = 0
Y = 0
for i in range(len(L)):
for k in range(summ, L[i] - 1, -1):
if A[k - L[i]]:
t = A[k - L[i]] | (2 << i)
if A[k]:
common = A[k] & t
X = A[k] ^ common
Y = t ^ common
break
else:
A[k] = t
if X:
break
first = [L[i] for i in range(len(L)) if (X & (2 << i))]
second = [L[i] for i in range(len(L)) if (Y & (2 << i))]
print(first, second)
>>> [2, 11, 29] [5, 37]
In this example code finds equal sums 59
for [2, 11, 17, 29] and [5, 17, 37]
and removes common 17
to get final results with sum 42
It is not obligatory to store sets in A[]
cells - we can store the last item of sum, then unwind item sequence
L = [2,5,11,17,29,37,43]
summ = sum(L)
A =[0]*(summ+1)
A[0] = -1
last = 0
for i in range(len(L)):
for k in range(summ, L[i] - 1, -1):
if A[k - L[i]]:
t = L[i]
if A[k]:
last = k
break
else:
A[k] = t
if last:
break
first = set()
k = last
while k:
first.add(A[k])
k = k - A[k]
second = set()
second.add(t)
k = last - t
while k:
second.add(A[k])
k = k - A[k]
print(first.difference(second),second.difference(first))
>>> {2, 11, 29} {37, 5}
Upvotes: 2