views:

417

answers:

4

I think that stackoverflow is rendering me even lazier than usual, but...

The problem is simpler than knapsack (or a type of it, without values and only positive weights). It consists on checking if a number can be a combination of others, and the function shall return true or false.

Ex: 112 and a list with { 17, 100, 101 } should return false, 469 with the same list should return true, 35 should return false, 119 true, etc...

Any ideas? Thanks!

Edit: subset sum problem would be more accurate for this than knapsack.

+2  A: 

An observation that will help you is that if your list is {a, b, c...} and the number you want to test is x, then x can be written as a sum of a sublist only if either x or x-a can be written as a sum of the sublist {b, c, ...}. This lets you write a very simple recursive algorithm to solve the problem.

edit: here is some code, taking into account the comments below. Not tested so probably buggy; and not necessarily the fastest. But for a small dataset it will get the job done neatly.

bool is_subset_sum(int x, std::list::const_iterator start, std::list::const_iterator end)
{
  // for a 1-element list {a} we just need to test a|x
  if (start == end) return (x % *start == 0); 

  // if x is small enough  we don't need to bother testing x - a
  if (x<a) return is_subset_sum (x, start+1, end);

  // the default case. Note that the shortcut properties of || means the process ends as soon as we get a positive.
  return (is_subset_sum (x, start+1, end) || is_subset_sum (x-a, start, end));
}
Tom Smith
What about multiples of a?
JXG
Well, if it has to sum x and there are no negative integers, maybe I can use a common (zero-sum) implementation with a subset like: { -x, a, b, c ... }
huff
Ah, ok. I was interpreting the question as simply taking the sum of a subset of the list. If you're allowing positive multiples then you need to test x, x-a, x-2a, and so on. If you're allowing negative multiples then of course the test boils down to does gcd(a,b,c...) go into x.
Tom Smith
The recursive step would be a little more complex: either `a` is part of the solution and then `x-a` can be calculated in terms of `{ a, b, c }`, or `a` is not part of the solution and `x` can be written in terms of `{ b, c }`. In any case you are reducing the size of the problem (either a smaller number or a smaller set). Now the search space may be greater than what you want to do with the naïve implementation...
David Rodríguez - dribeas
+3  A: 

This is a special case of the Subset Sum problem, with sets that only contain one negative number (i.e., express 112 and { 17, 100, 101 } as { -112, 17, 100, 101 }). There's a few algorithms on the Wikipedia page, http://en.wikipedia.org/wiki/Subset_sum_problem.

Dietrich Epp
Indeed.........
huff
That still doesn't account for multiples of numbers in the set. Although subset sum with multiples would be applicable, since the negative number can be multiplied.
Potatoswatter
+2  A: 

Note that positive results become denser as the queried number becomes larger. For example, all numbers greater than 100^2 can be generated by { 17, 100, 101 }. So the optimal algorithm may depend upon whether the queried number is much greater than the set's members. You might look into field theory.

At the least, you know the result is always false if the greatest common divisor of the set is not in the query, and that can be checked in negligible time.

Potatoswatter
+1  A: 

If the number to reach is not too large, you can probably generate all the reachable numbers from the set that fall in the range [1,N].

Problem: Reach N using the elements in the list L, where N is small enough not to worry about a vector of size N elements' size.

Algorithm:

  • Generate a vector V of size N
  • For each element l in the list L
    • For each reachable element v in V
      • mark all elements v + n*l in V as reachable
David Rodríguez - dribeas
I really like that approach, considering that the list doesn't change, and that the maximum number isn't quite big.
huff
Also known as a sieve. It's the first thing that came to my mind, just in CS "this algorithm works for small numbers" is frowned upon. Don't forget to use a `bitset` to raise the upper limit by an order of magnitude.
Potatoswatter