views:

654

answers:

7

Hello, I am looking for a method to determine if there is a solution to equations such as: 3n1+4n2+5n3=456, where n1,n2,n3 are positive integers.

Or more general: are there zero or positive integers n1,n2,n3... that solves the equation k1n1+k2n2+k3n3...=m where k1,k2,k3... and m are known positive integers.

I don't need to find a solution - just to determine if a solution exist.

Edit:

Concerning the practical use of this algorithm:

In a communication library, I want to decide if a given message is valid according to its size, before handling the message. For example: I know that a message contains zero-or-more 3-bytes elements, zero-or-more 4-bytes elements, and zero-or-more 5-bytes elements. I received a message of 456 bytes, and I want to determine its validity before further inspecting its content. Of course the header of the message contains the number of elements of each type, but I want to make a first-inspection in the communication-library level by passing something like pair<MsgType,vector<3,4,5>>.

+2  A: 

Looks like you're talking about a system of inequalities with integer constraints. The reality is you're solving for this system:

k1n1+k2n2+k3n3...=m
n1 >= 0
n2 >= 0
n3 >= 0

And the additional constraint that n1, n2, n3 are integers. That's a linear programming problem. Unfortunately for you, the general case of solving such a system with integer constraints is NP-complete. However, there are many algorithms that will solve it for you.

Welbog
No, this is different. The NP-complete problem is looking for whether or not there is a solution to certain inequality, not a solution to an equality.
Jason
@Jason: Not noticing the three inequalities in the above system of inequalities? Just what do you think `>= 0` means?
Welbog
I'm sorry for not being clear. The NP-complete linear programming problem is trying to decide whether or not a there is a integer solution to a linear system of inequalities. That is, are there integers x_1, x_2, ... x_n so that Ax >= b. Here A is an m x n integer matrix, and b is an integer m-vector. This is very different than solving a linear equation.
Jason
@Jason: How is it different? You need only introduce a free variable into the first equation and force it to be greater than 0 to turn the first equation into an inequality, then you can write the problem as `Ax >= b`. There are more inequalities than equalities in this situation, and linear programming methods will definitely solve it, and I'm not convinced you can reduce this to a P solution. Certainly no one has identified such a solution yet in this thread.
Welbog
@Welbog: How are you adjusting the matrix A and the vector b?
Jason
+1  A: 

A brute-force approach (pseudocode):

def a = 3
def b = 4
def c = 5
def x = 456

for n1 = a to int(x / a) + 1 step a
  for n2 =b to int(x / b) + 1 step b
    for n3 = c to int(x / c) + 1 step c
      if a * n1 + b * n2 + c * n3 = x then
        print n1, n2, n3

See also http://mail.python.org/pipermail/python-list/2000-April/031714.html

EDIT: In a communications library this would make no sense, since it needs to work immediately. In the OP's application I would probably use some sort of hash, but his approach sounds interesting.

Robert Harvey
OK, why the downvote? The solution works.
Robert Harvey
This brute force solution can be heavily optimized from here.
Jason Punyon
Three unknowns on the LHS and 456 as the RHS is a specific example, not the general problem.
Jason
I never said it was efficient, I just said it was a solution. Even at 3.5 million loops (152*152*152) it should still only take a second or two to run.
Robert Harvey
@Jason, You can substitute your own values for the coefficients.
Robert Harvey
@Robert Harvey: There might be more than three unknowns too. This is a horrific problem to get around (`goto`s anyone?) and scales horrifically badly.
Jason
Added some simple optimizations. This gets it down to 1.6 million loops (152 * 114 * 92)
Robert Harvey
Additional optimizations: New code steps through each factor, rather than through each integer. The new code has 152/3 * 114/4 * 92/5 loops, approximately 27550. Still probably slower than a hash.
Robert Harvey
+3  A: 

According to this, if the greatest common factor of {n1, n2, n3, ...} is not a divisor of m then you have no solution. This page shows an example of just {n1, n2} but it extends to larger systems. The new problem is writing an algorithm for finding the greatest common factor, but that's trivial in light of the original problem.

So part of your algorithm would find the gcf({n1,n2,...}) then see if it's a factor of m. If it isn't, then no solution exists. This doesn't fully show that a solution exists, but it can quickly show you that none exists, which is still useful.

dharga
I think for certain conditions, if you find a solution, you can find infinite integer solutions.
Calyth
+1  A: 

Here's something on the 2 number case. I haven't figured out yet how to scale it:

Given 2 relatively prime integers x and y, there exist positive integers a and b such that ax+by=c for all c>=(x-1)(y-1)

Basically, this works because, if you assume x<y, you can express all integers mod x with (0, y, 2y, 3y, ..., (x-1)y). Now, by adding some positive multiple of x, you can reach all integers between [(x-1)(y-1),(x-1)y], as all of the integers between (x-1)(y-1) and (x-1)y-1 had been expressed previously.

  1. GCD(x,y). If c is not a multiple, return false.
  2. if GCD(x,y) > 1, divide x,y,c by GCD
  3. If c > (x-1)(y-1), return true
  4. Else brute force

And for the brute force:

if int(c/y) >= c*y^(-1) mod x, return true, 
else return false
Joe Arasin
+3  A: 

This is related to the Frobenius coin problem, which hasn't been solved for n>3.

lhf
+6  A: 

You're asking if the regular expression

(xxx|xxxx|xxxxx)*

matches xx...x, where x occurs 456 times.

Here's a solution in O(n+a^2), where a is the smallest of the numbers on the left side (in this case 3).

Suppose your numbers are 6,7,15. I'll call a number expressible in the form 6x+7y+15z "available". You are to check if a given number is available.

If you're able to get some number n, then surely you will be able to get n+6, n+12, n+18 - in general, n+6k for all k >= 0. On the other side, if you are unable to get some number n, then n-6 is surely not available too (if you could get (n-6), then (n-6)+6=n would be available), this means n-12, n-18, n-6k are not available neither.

Suppose you have determined that 15 is available but 9 is not. In our case, 15=6*0+7*0+15*1 but won't be able to get 9 in any way. So, by our previous reasoning, 15+6k is available for all k >= 0 and 9-6k for all k >= 0 is not. If you've got some number that divided by 6 gives 3 as remainder (3, 9, 15, 21, ...) you can quickly answer: numbers <= 9 are not available, numbers >= 15 are.

It is enough to determine for all possible remainders of division by 6 (that is 0,1,2,3,4,5) what is the smallest number that is available. (I just have shown that this number for the remainder 3 is 15).

How to do it: Create a graph with vertices 0,1,2,3,4,5. For all numbers k that you are given (7,15 - we disregard 6) add an edge from x to (x + k) mod 6. Give it weight (x + k) div 6. Use Dijkstra's algorithm using 0 as the initial node. The distances found by the algorithm will be exactly those numbers we are searching for.

In our case (6,7,15) the number 7 gives rise to 0 -> 1 (weight 1), 1 -> 2 (weight 1), 2 -> 3 (weight 1), ..., 5 -> 0 (weight 1) and the number 15 gives 0 -> 3 (weight 2), 1 -> 4 (weight 2), ..., 5 -> 1 (weight 2). The shortest path from 0 to 3 has one edge - its weight is 2. So 6*2 + 3 = 15 is the smallest number that gives 3 as remainder. 6*1 + 3 = 9 is not available (well, we checked that previously by hand).

And what is the connection to regular expressions? Well, every regular expression has an equivalent finite automaton, and I constructed one of them.

This problem, with multiple queries allowed, appeared on the Polish Olympiad and I translated the solution. Now, if you hear now a person saying computer science is not useful for real programmers, punch him in face.

sdcvvc
Definitely non-standard, but I love it! Reminds me of my days in Theory of Computation talking about Chomsky and the good ol' Pumping Lemma ;) +100 for the punch in the face ;)
dharga
Very, very neat solution. You could also include a bit more info on how the graph can be used as an automaton. My impression is that the automaton is NFA and for example to process 6+7+15=28, 28 % 6 = 4, thus the accepting state would be the node 4, and you have (28 - 4) / 6 = 4 tokens to process, and each edge consumes as many tokens as its weight. Is this right? Also, what's the story of the problem? Is it in a textbook? Or someone came up with the solution in the olympiad?
Dimitris Andreou
Your description is correct. The path goes 0 -> 1 -> 4, where the first edge means adding 7 (weight 1), and the second edge means adding 15 (weight 2); this consumes 3 tokens - the fourth one is taken by using number 6 once. In http://stackoverflow.com/questions/2912885/ Moron gives a link with more information about the problem. I don't know the story how jury chose the task. Three participants (out of 42) scored maximum points (task "sum"): http://www.oi.edu.pl/php/show.php?ac=e180912.
sdcvvc
+1  A: 

Perhaps the following info is irrelevant, because it doesn't handle the general situation, but...

If the problem is to determine whether a given positive integer K can be formed as a sum 3*n1 + 4*n2 + 5*n3, for nonnegative integers n1, n2, n3, then the answer is "yes", for K >= 3.

Rosen's well-known textbook Discrete Mathematics and its Applications, p. 287 of the sixth edition, proves that "every amount of postage of 12 cents or more can be formed using just 4-cent and 5-cent stamps," using induction.

The basis step is that postage of 12 cents can be formed with 3 four-cent stamps.

The induction step considers that if P(k) is true using four-cent stamps, then simply substitute a four-cent stamp with a five-cent stamp to show that P(k+1) is true. If P(k) is true using no four-cent stamps, then, because k>=12, we need at least 3 five-cent stamps to form our sum, and 3 five-cent stamps can be replaced with 4 four-cent stamps to achieve k+1.

To extend the above solution for this problem requires just considering just a few more cases.

bbg