Reputation: 93
Given an array of integers A and integers N, M. I want to find all the subsets S of A where (sum(S) mod M = N). A can have multiple integers of the same value. In my case N will be in the range 0<=n<=31, M will be 32 and A will contain integers in the same range as n.
Is there any good/"fast" way to do this?
Thanks!
Upvotes: 5
Views: 1901
Reputation: 23955
If you'd just like to count them, we can solve it in O(|A| * M)
with dynamic programming. Here's an example:
A = [2, 6, 4, 3]
M = 5
0 1 2 3 4
S = 0 0 0 0 0 // The number of subsets with sum i (mod M)
// Iterate over A (through S each time)
2 0 0 1 0 0
6 0 1 1 1 0
4 1 2 2 1 1
3 3 3 3 3 3
Python code:
A = [2, 6, 4, 3]
M = 5
S = [0 for i in range(0, M)]
for a in A:
STemp = [0 for i in range(0, M)]
for (i, v) in enumerate(S):
ii = (a + i) % M
STemp[ii] = S[ii] + v
STemp[a % M] = STemp[a % M] + 1
S = STemp
print(S) # [3, 3, 3, 3, 3]
Upvotes: 2
Reputation: 842
It is solvable in O(2n/2 log2(2n/2)) = O(2n/2 (n/2)), with your constrains this works on C++ less than a second.
All you need is:
1) compute all possible sums of first n/2
elements of the array and put them in map<int, int> left
where left[sum] =
how many times sum appears at the left part of the array
2) compute all possible sums of last n/2
elements of the array and for each sum S
check does map left
contains value (N - S + M)%M
to find all possible sums you could use bitmasks:
for (int mask = 1; mask < pow(2, n/2); mask++) {
int sum = 0;
for (int i = 0; i < n/2; i++)
if ( (int) (mask & (1<<i)) )
sum += A[i];
}
Upvotes: 2