Choose numbers which sum to zero - algorithm

There is N number of sets, each containing various number of integers, e.g.:
(-2, -1, 0), (-1,4), (-2, 2, 3), (-3, -2, 4, 6), (-2)
How to pick exactly one number from each set so that these N integers sum to zero? For example:
-1, -1, 2, -2, 4, -2
Note there might be no solution or multiple (in which case it doesn't matter which one I choose).
I was thinking that I can do breath-first search but was wondering if there are any other, preferably faster, ways to solve this.

Let dp[i, j] = true iff we can make sum j using one number from each of the sets 1, 2, ..., i.
dp[i, 0] = true for all i
for i = 1 to numSets do
for num = 1 to sets[i].Count do
for j = maxSum - sets[i, num] downto -maxSum do
dp[i, j + sets[i, num]] |= dp[i - 1, j]
You can use a map to handle negative indexes or add an offset to make them positive. maxSum is the maximum value your sum can take (for example sum of maximums of all sets or sum of absolute values of minimums, whichever is larger). There might be ways to update maxSum as you go as an optimization.
For your example, this will run like so:
(-2, -1, 0), (-1,4), (-2, 2, 3), (-3, -2, 4, 6), (-2)
Iteration over the first set will give dp[1, -2] = dp[1, -1] = dp[1, 0] = true.
Iteration over the second will give dp[2, -3] = true (because dp[2, -2 + -1] |= dp[1, -1] = true), dp[2, -2] = true (because dp[2, -1 + -1] |= dp[1, -1] = true) etc.
If dp[numSets, 0] = true, there is a solution, which you can reconstruct by keeping tracking of which last number you picked for each dp[i, j].
The complexity is O(numSets * K * maxSum), where K is the number of elements of a set. This is pseudopolynomial. It might be fast enough if your values are small. If your values are large but you have few sets with few elements, you are better off bruteforcing it using backtracking.

This seems related to the subset sum problem: given a set n integers, is there a subset that sums to 0? That problem is known to be NP-complete and that, in short, means your chances are very small of finding a fast way of doing this.
For one set of integers it's hard enough and in your problem another constraint is added that one integer must be selected from each set. A search algorithm is indeed the way to go but in the worst case you won't be doing much better than an exhaustive search.

Related

Use FFT to find all possible fixed-size subset sums

I need to solve the following problem: given an integer sequence x of size N, and a subset size k, find all the possible subset sums. A subset sum is the sum of elements in the subset.
If elements in x are allowed to appear many times (up to k of course) in a subset (sub-multiset), this problem has a pseudo polynomial time solution via FFT. Here is an example:
x = [0, 1, 2, 3, 6]
k = 4
xFrequency = [1, 1, 1, 1, 0, 0, 1] # On the support of [0, 1, 2, 3, 4, 5, 6]
sumFrequency = selfConvolve(xFrequency, times = 4) # A fast approach is to simply raise the power of the Fourier series.
sumFrequency > 0 # Gives a boolean vector indicating all possible size-k subset sums.
But what can be done if an element cannot show up multiple times in a subset?
I came up with the following method but am unsure of its correctness. The idea is to first find the frequencies of sums that are produced by adding at least 2 identical elements:
y = [0, 2, 4, 6, 12] # = [0, 1, 2, 3, 6] + [0, 1, 2, 3, 6]
yFrequency = [0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1]
sumFrequencyWithRedundancy = convolve(yFrequency, x, x)
My reasoning is that since y represents all possible sums of 2 identical elements, then every sum in y + x + x is guaranteed to have been produced by adding at least 2 identical elements. Finally
sumFrequencyNoRedundancy = sumFrequency - sumFrequencyWithRedundancy
sumFrequencyNoRedundancy > 0
Any mistake or any other established method for solving the problem?
Thanks!
Edits:
After some tests, it does not work. There turns out to be much more combinations that should be excluded from sumFrequency besides sumFrequencyWithRedundancy, and the combinatoric analyses seem to escalate rapidly with k, eventually making it less efficient than brute-force summation.
My motivation was to find all possible sample sums given sampling without replacement and the sample size. Then I came across the idea of solving the standard subset sum problem via FFT --- free subset size and the qualified subsets themselves unneeded. The reference materials can be easily found online, basically a divide and conquer approach:
Divide the superset into 2 sets, left and right.
Compute all possible subset sums in the left and right sets. The sums are represented by 2 boolean vectors.
Convolve the 2 boolean vectors.
Find if the target sum is indicated in the final boolean vector.
You can see why the algorithm works for the standard subset sum problem.
If anyone can let me know some work on how to find all possible size-k subset sums, I would really appreciate it!
Given k and the n-element array x, it suffices to evaluate the degree-k coefficient in z of the polynomial
n x[i]
product (1 + y z).
i=1
This coefficient is a polynomial in y where the exponents with nonzero coefficients indicate the sums that can be formed using exactly k distinct terms.
One strategy is to split x with reasonably balanced sums, evaluate each half mod z^(k+1), and then multiply using the school algorithm for the outer multiplications and FFT (or whatever) for the inner. This should end up costing roughly O(k^2 S log^2 S).
The idea for evaluating elementary symmetric polynomials efficiently is due to Ben-Or.

choose k from n with a probability

I've a list of n elements (e_i). For each i, e_i have a probability p_i to be selected.
I want to write an algorithm to pick k elements from theses n, but I have to respect the probabilities of each element when I choose them. I've no idea how to do that, I didn't know any algorithm which do that :/
Can you direct my reflection?
Let's say you have 3 possible values: A, B, C and:
P(A) = 0.2, P(B) = 0.3, P(C) = 0.5. Then you will put the cumulative probabilities in an array p = [0.2, 0.5, 1]. In each pick you will generate a random number in the range [0, 1] (using the built in library of the language you use). Based on that number, you will return as a response the smallest number which is greater or equal to the randomly generated number (actually the class which corresponds to that number A, B or C).
Hint: that class can be obtained in O(logN) time, if the optimal approach is used.
Here is an example:
if you generate value of 0.4, then you will return B, because 0.5 is the smallest number >= 0.4. If you generate 0.01 you will return A.
That's the idea, I'll let you try implement that. If you need more help, I could write some (pseudo)code too.
Assuming that you want k distinct elements, you could do the following: keep track of the total remaining probability of the non-selected elements. Repeatedly (k times) pick a random number, r, in the range [0,remaining]. Scan over the probabilities, accumulating the probabilities until the sum exceeds r. Pick the corresponding element. Then -- reduce remaining by this probability and then zero the probability of that element so that it won't be picked again.
Here is a Python implementation:
from random import random
def choose(probs,k):
choices = []
remaining = 1
p = probs[:] #create a local copy
for i in range(k):
r = remaining * random()
i = 0
s = p[i]
while s < r:
i += 1
s += p[i]
choices.append(i)
remaining -= p[i]
p[i] = 0 #so won't be chosen again
return choices
#test:
dist = [0.2, 0.4, 0.1, 0.1, 0.1, 0.05, 0.05]
for i in range(10):
print(choose(dist,4))
Typical output:
[2, 5, 1, 3]
[1, 0, 6, 4]
[0, 4, 1, 6]
[1, 2, 3, 0]
[1, 5, 2, 4]
[3, 1, 0, 2]
[1, 2, 0, 4]
[1, 2, 0, 4]
[2, 5, 1, 4]
[1, 2, 0, 3]
Note how 0 and 1 are frequently chosen but 5 and 6 are comparatively rare.
As an implementation detail: the above algorithm should always work in principle, but it is possible that round-off error and a value of r which is extremely close to remaining could lead to a subscript out of range error. For some use cases this should be so rare that you need not worry about it, but you could add error-trapping to e.g. pick the element with the last non-zero probability in the cases that the sum of all non-zero probabilities rounds to just below remaining and the r chosen happens to fall in that narrow gap.
So element ix can be expressed as (e_ix, p_ix), as those are its two components. You apparently already know what values to fill in for all of these. I am going to come up with an example though, so I can show you how to do this without doing it for you:
(A, 1) (B, 2) (C, 3)
What you need to do is assign each value to a range. I'll do it an easy way and just go left to right, starting at zero.
So, we need 1 slot for A, 2 for B, 3 for C. Our possible indices will be 0, 1, 2, 3, 4, and 5.
0->A
1->B
2->B
3->C
4->C
5->C
This is a basic example, and your weights might be floating point, but it should give you a start.
Edit: Floating point example
(D, 2) (E, .5123) (F, 1)
D < 2
2 <= E < 2.5123
2.5123 <= F < 3.5123
Necessary assumption
By linearity of the expectation, it is easy to show that if you pick elements among the n elements 0, 1, 2, ..., n-1 such that each element i has probability p_i of being selected, then the expectation of the number of picked elements is exactly sum p_i. This holds no matter the algorithm used to pick the elements.
You are looking for such an algorithm, but with the added constraint that the number of picked elements is always k. It follows that a necessary assumption is:
sum p_i = k
Fortunately, it turns out that this assumption is also sufficient.
Algorithm
Assume now that sum p_i = k. The following algorithm will select exactly k elements, such that each element i in 0,1,...,n-1 has probability p_i of being chosen.
Compute the cumulative sums:
c_0 = 0
c_1 = p_0
...
c_i = p_0 + p_1 + ... + p_(i-1)
...
c_n = k
Pick a number x uniformly at random in [0,1[
For every number y in the list x, 1+x, 2+x, 3+x, ..., k-1+x:
Choose element i such that c_i <= y < c_(i+1)
It is easy to verify that exactly k elements are chosen, and that every element i has probability p_i of being chosen.
Reference
The previous algorithm is the subject of a research paper from the 80s or 90s, which I can't put my hands on at this exact moment; I will edit this post with a reference if I can find it again.

Find a subset with sum within a range

How can I find a subset of an array that the sum of its elements is within a given range?
For example:
let a = [ 1, 1, 3, 6, 7, 50]
let b = getSubsetSumRange(3, 5)
so b could potentially be [1, 1, 3], [1, 3], [3], [1, 3]; It doesn't matter the order I only need one of them.
You would probably like to use dynamic programming approach to solve this problem.
Let F[i][j] have value true if it is possible to select some numbers among numbers from the original subset a[1..i] so that their sum is equal to j.
i would obviously vary from 1 to length of a, and j from 0 to max inclusively, where max is the second number from your given range.
F[i][0] = true for all i by definition (you can always select empty subset).
Then F[i][j] = F[i - 1][j - a[i]] | F[i - 1][j]
Logically it means that if you can select a subset with sum j from elements 1..i-1, then you obviously can do it with the subset 1..i, and if you can select a subset with sum j - a[i] from elements 1..i-1, then by adding your new element a[i] to that subset, you can get your desired sum j.
After you have calculated the values of F, you can find any F[n][j] that is true for values j lying in your desired range.
Say you have found such number k. Then the algorithm to find the required set would look like that:
for i = n..1:
if F[i - 1][k - a[i]] == True then
output a[i] to the answer
k -= a[i]
if k == 0
break

Permutation At A Railway Track(Stack Implementation)

Engines numbered 1, 2, ..., n are on the line at the left, and it is desired to rearrange(permute) the engines as they leave on the right-hand track. An engine that is on the spur track can be left there or sent on its way down the right track, but it can never be sent back to the incoming track. For example if n = 3, and we ha the engines numbered 1,2,3 on the left track, then 3 first goes to the spur track. We could then send 2 to the spur, then on the way to its right,then send 3 on the way, then 1, obtaining the new order 1,3,2.
We have to find all the possible permutations for specific n.
For n=1, answer = 1;
For n=2 answer = 2;
For n=3 answer = 5;
Didn't find any generality.
Using Stack Implementation would be very helpful.
But any solution is welcomed.
p.s. This is not a homework question, as I am a self taught person.
Here's my attempt at a recursive solution (see comments in Java code):
private static int result = 0;
private static int n = 3;
public static void g(int right,int spur){
if (right == n) // all trains are on the right track
result++;
else if (right + spur < n) // some trains are still on the left track
g(right,spur + 1); // a train moved from the left track to the spur
if (spur > 0) // at least one train is on the spur
g(right + 1,spur - 1); // a train moved from the spur to the right track
// (also counts trains moving directly from the left to right track)
}
public static void main (String[] args){
g(0,0);
System.out.println(result); // 5
}
The recursive solution above actually counts each possibility. For a combinatorial solution we consider all combinations of n movements on and out of the spur, where adjacent such movements are equivalent to movements directly from the left to right track. There are 2n choose n such combinations. Now let's count the invalid ones:
Consider all combinations of (n - 1) ins and (n + 1) outs of the spur. All these include a point, p, where a train is counted as leaving the spur when no trains are on it. Let's say that p has k ins and (k + 1) outs preceding it - then the number of remaining ins is (n - 1 - k); and remaining outs, (n + 1) - (k + 1) = (n - k).
Now reverse the ins and outs for each one of these combinations starting after p so that in becomes out and out in. Each one of the reversed sections has necessarily (n - k) ins and (n - 1 - k) outs. But now if we total the number of ins and outs before and after p we get k + (n - k) = n ins, and (k + 1) + (n - 1 - k) = n outs. We have just counted the number of combinations of n ins and n outs that are invalid. If we assume that one such combination may not have been counted, theoretically reverse that combination after its p and you will find a combination of (n - 1) ins and (n + 1) outs that was not counted. But by definition we counted them all already so our assumed extra combination could not exist.
Total valid combinations then are 2n choose n - 2n choose (n + 1), the Catalan numbers.
(Adapted from an explanation by Tom Davis here: http://mathcircle.berkeley.edu/BMC6/pdf0607/catalan.pdf)
First, note that you may ignore the possibility of moving the train from incoming directly to outgoing: such a move can be done by moving a train to the spur and then out again.
Denote a train move from incoming to spur as ( and a train move from spur to outgoing as ), and you get a bijection between permutations of the trains and strings of n pairs of correctly balanced parenthesis. That statement needs proving, but the only hard part of the proof is proving that no two strings of balanced parentheses correspond to the same permutation. The number of such strings is the n'th Catalan number, or choose(2n, n)/(n+1), where choose(n, k) is the number of ways of choosing k items from n.
Here's code to compute the solution:
def perms(n):
r = 1
for i in xrange(1, n+1):
r *= (n + i)
r //= i
return r // (n + 1)
You can generate all the permutations with this code, which also exposes the Catalan nature of the solution.
def perms(n, i=0):
if n == 0:
yield []
for k in xrange(n):
for s in perms(k, i+1):
for t in perms(n-k-1, i+k+1):
yield s + [i] + t
print list(perms(4))
Output:
[[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1],
[0, 3, 2, 1], [1, 0, 2, 3], [1, 0, 3, 2], [1, 2, 0, 3],
[2, 1, 0, 3], [1, 2, 3, 0], [1, 3, 2, 0], [2, 1, 3, 0],
[2, 3, 1, 0], [3, 2, 1, 0]]
The status of the system can be described by giving the 3 (ordered!) lists of engines, in the left, spur and right tracks. Given the status, it is possible to calculate all the possible moves. This creates a tree of possibilities: the root of the tree is the initial status, and every move corresponds to a branch which leads to a new status. The final status at the end of a branch (a leaf) is your final position in the right track.
So, you have to build and explore all the tree, and at the end you have to count all the leaves. And the tree is a common data structure.
Just to clarify, the tree in this case wouldn't replace the stacks. The stacks are used to store your data (the position of the engines); the tree is used to track the progress of the algorithm. Every time you have a status (a node of the tree) you have to analyse your data (=the content of the stacks) and find the possible moves. Every move is a branch in the tree of the algorithm, and it leads to a new status of the stacks (because the engine has moved). So basically you will have one "configuration" of the 3 stacks for each node of the tree.

Rank the suffixes of a list

ranking an element x in an array/list is just to find out how many elements in the array/list that strictly smaller than x.
So ranking a list is just get ranks of all elements in the list.
For example, rank [51, 38, 29, 51, 63, 38] = [3, 1, 0, 3, 5, 1], i.e., there are 3 elements smaller than 51, etc.
Ranking a list can be done in O(NlogN). Basically, we can sort the list while remembering the original index of each element, and then see for each element, how many before it.
The question here is How to rank the suffixes of a list, in O(NlogN)?
Ranking the suffixes of a list means:
for list [3; 1; 2], rank [[3;1;2]; [1;2]; [2]]
note that elements may not be distinct.
edit
We don't need to print out all elements for all suffixes. You can image that we just need to print out a list/array, where each element is a rank of a suffix.
For example, rank suffix_of_[3;1;2] = rank [[3;1;2]; [1;2]; [2]] = [2;0;1] and you just print out [2;0;1].
edit 2
Let me explain what is all suffixes and what means sorting/ranking all suffixes more clearly here.
Suppose we have an array/list [e1;e2;e3;e4;e5].
Then all suffixes of [e1;e2;e3;e4;e5] are:
[e1;e2;e3;e4;e5]
[e2;e3;e4;e5]
[e3;e4;e5]
[e4;e5]
[e5]
for example, all suffixes of [4;2;3;1;0] are
[4;2;3;1;0]
[2;3;1;0]
[3;1;0]
[1;0]
[0]
Sorting above 5 suffixes implies lexicographic sort. sorting above all suffixes, you get
[0]
[1;0]
[2;3;1;0]
[3;1;0]
[4;2;3;1;0]
by the way, if you can't image how 5 lists/arrays can be sorted among them, just think of sorting strings in lexicographic order.
"0" < "10" < "2310" < "310" < "42310"
It seems sorting all suffixes is actually sorting all elements of the original array.
However, please be careful that all elements may not be distinct, for example
for [4;2;2;1;0], all suffixes are:
[4;2;2;1;0]
[2;2;1;0]
[2;1;0]
[1;0]
[0]
then the order is
[0]
[1;0]
[2;1;0]
[2;2;1;0]
[4;2;2;1;0]
As MBo noted correctly, your problem is that of constructing the suffix array of your input list. The fast and complicated algorithms to do this are actually linear time, but since you only aim for O(n log n), I will try to propose a simpler version that is much easier to implement.
Basic idea and an initial O(n log² n) implementation
Let's take the sequence [4, 2, 2, 1] as an example. Its suffixes are
0: 4 2 2 1
1: 2 2 1
2: 2 1
3: 1
I numbered the suffixes with their starting index in the original sequence. Ultimately we want to sort this set of suffixes lexicographically, and fast. We know we can represent each suffix using its starting index in constant space and we can sort in O(n log n) comparisons using merge sort, heap sort or a similar algorithm. So the question remains, how can we compare two suffixes fast?
Let's say we want to compare the suffixes [2, 2, 1] and [2, 1]. We can pad those with negative infinity values changing the result of the comparison: [2, 2, 1, -∞] and [2, 1, -∞, -∞].
Now the key idea here is the following divide-and-conquer observation: Instead of comparing the sequences character by character until we find a position where the two differ, we can instead split both lists in half and compare the halves lexicographically:
[a, b, c, d] < [e, f, g, h]
<=> ([a, b], [c, d]) < ([e, f], [g, h])
<=> [a, b] < [e, f] or ([a, b,] = [e, f] and [c, d] < [g, h])
Essentially we have decomposed the problem of comparing the sequences into two problems of comparing smaller sequences. This leads to the following algorithm:
Step 1: Sort the substrings (contiguous subsequences) of length 1. In our example, the substrings of length 1 are [4], [2], [2], [1]. Every substring can be represented by the starting position in the original list. We sort them by a simple comparison sort and get [1], [2], [2], [4]. We store the result by assigning to every position it's rank in the sorted lists of lists:
position substring rank
0 [4] 2
1 [2] 1
2 [2] 1
3 [1] 0
It is important that we assign the same rank to equal substrings!
Step 2: Now we want to sort the substrings of length 2. The are only really 3 such substrings, but we assign one to every position by padding with negative infinity if necessary. The trick here is that we can use our divide-and-conquer idea from above and the ranks assigned in step 1 to do a fast comparison (this isn't really necessary yet but will become important later).
position substring halves ranks from step 1 final rank
0 [4, 2] ([4], [2]) (2, 1) 3
1 [2, 2] ([2], [2]) (1, 1) 2
2 [2, 1] ([2], [2]) (1, 0) 1
3 [1, -∞] ([1], [-∞]) (0, -∞) 0
Step 3: You guessed it, now we sort substrings of length 4 (!). These are exactly the suffixes of the list! We can use the divide-and-conquer trick and the results from step 2 this time:
position substring halves ranks from step 2 final rank
0 [4, 2, 2, 1] ([4, 2], [2, 1]) (3, 1) 3
1 [2, 2, 1, -∞] ([2, 2], [1, -∞]) (2, 0) 2
2 [2, 1, -∞, -∞] ([2, 1], [-∞,-∞]) (1, -∞) 1
3 [1, -∞, -∞, -∞] ([1,-∞], [-∞,-∞]) (0, -∞) 0
We're done! If our initial sequence would have had size 2^k, we would have needed k steps. Or put the other way round, we need log_2 n steps to process a sequence of size n. If its length is not a power of two, we just pad with negative infinity.
For an actual implementation we just need to remember the sequence "final rank" for every step of the algorithm.
An implementation in C++ could look like this (compile with -std=c++11):
#include <algorithm>
#include <iostream>
using namespace std;
int seq[] = {8, 3, 2, 4, 2, 2, 1};
const int n = 7;
const int log2n = 3; // log2n = ceil(log_2(n))
int Rank[log2n + 1][n]; // Rank[i] will save the final Ranks of step i
tuple<int, int, int> L[n]; // L is a list of tuples. in step i,
// this will hold pairs of Ranks from step i - 1
// along with the substring index
const int neginf = -1; // should be smaller than all the numbers in seq
int main() {
for (int i = 0; i < n; ++i)
Rank[1][i] = seq[i]; // step 1 is actually simple if you think about it
for (int step = 2; step <= log2n; ++step) {
int length = 1 << (step - 1); // length is 2^(step - 1)
for (int i = 0; i < n; ++i)
L[i] = make_tuple(
Rank[step - 1][i],
(i + length / 2 < n) ? Rank[step - 1][i + length / 2] : neginf,
i); // we need to know where the tuple came from later
sort(L, L + n); // lexicographical sort
for (int i = 0; i < n; ++i) {
// we save the rank of the index, but we need to be careful to
// assign equal ranks to equal pairs
Rank[step][get<2>(L[i])] = (i > 0 && get<0>(L[i]) == get<0>(L[i - 1])
&& get<1>(L[i]) == get<1>(L[i - 1]))
? Rank[step][get<2>(L[i - 1])]
: i;
}
}
// the suffix array is in L after the last step
for (int i = 0; i < n; ++i) {
int start = get<2>(L[i]);
cout << start << ":";
for (int j = start; j < n; ++j)
cout << " " << seq[j];
cout << endl;
}
}
Output:
6: 1
5: 2 1
4: 2 2 1
2: 2 4 2 2 1
1: 3 2 4 2 2 1
3: 4 2 2 1
0: 8 3 2 4 2 2 1
The complexity is O(log n * (n + sort)), which is O(n log² n) in this implementation because we use a comparison sort of complexity O(n log n)
A simple O(n log n) algorithm
If we manage to do the sorting parts in O(n) per step, we get a O(n log n) bound. So basically we have to sort a sequence of pairs (x, y), where 0 <= x, y < n. We know that we can sort a sequence of integers in the given range in O(n) time using counting sort. We can intepret our pairs (x, y) as numbers z = n * x + y in base n. We can now see how to use LSD radix sort to sort the pairs.
In practice, this means we sort the pairs by increasing y using counting sort, and then use counting sort again to sort by increasing x. Since counting sort is stable, this gives us the lexicographical order of our pairs in 2 * O(n) = O(n). The final complexity is thus O(n log n).
In case you are interested, you can find an O(n log² n) implementation of the approach at my Github repo. The implementation has 27 lines of code. Neat, ain't it?
This is exactly suffix array construction problem, and wiki page contains links to the linear-complexity algorithms (probably, depending on alphabet)

Resources