-2

I was solving a task that was - a user is entering 3 numbers, a, b, c. The goal is to find if you can get to c summing a and b. In each step is allowed to add a to b, and b to a. I need to find if that is possible with the entered numbers. The entered numbers are in the range between 0 and 10^18. Below is my code, done with recursion.

Example of solving the task for a=4 b=6 c=38:

  1. a=4 b=10
  2. a=14 b=10
  3. a=14 b=24
  4. a=38 b=24 print YES

My code below does its job well for low numbers but I think I'm loosing the battle with the bigger numbers... I added few comments to what part is doing what.

What I need help is, I need it to work better, and faster, and I don't know how to optimise it more.

//the function that I'm using
int task(long long int a, long long int b, long long int c, long long int d, int p) 
{ //a, b and c are long long integers that are submited by the user, d is the sum of
  //the unchanged a and b, and p is a flag
    if(!a && !b && c) return 0; //0+0 will never get to 1
    if(c==d) return 1; //if I get with c to d, it is confirmed yes, 
                       //did the math with a pen :)
    if(c<d || c<=0) // I thought this is a nice case to stop
    {
        return 0;
    }
    if(p==1)
    {
        if(a>c) return 0; //if the flag p is one, that means i changed a, 
                          //so compare a
    }
    if(p==2)
    {
        if(b>c) return 0; //if p is two, i changed b so compare b
    }
    if(c-d>0) return task(a+b, b, c-b, d, 1)||task(a, b+a, c-a, d, 2);  
            //recursion call with OR operator so every step is checked

}//one part is a=a+b b=b c=c-b, i decrement c so fewer steps are needed, 
 //the other part is when i add a to b

int main()
{
    long long int a,b,c;
    scanf("%I64d%I64d%I64d",&a,&b,&c); //scaning
    int p; //the flag for the first numbers
    if(a>b) p=1; //i dont know if i need this step at all xD
    else p=2; //but to make sure
    if((a==1 || b==1) && c) printf("YES"); //a=1 b=1 and c>=1 means i can get to c,
                                           //even with a+b+b+b..
    else if(a==c || b==c) printf("YES"); //if one of the numbers are already same 
                                         //with c, no need to check
    else if(task(a,b,c,a+b,p)) printf("YES"); //if the function returns 1, print YES
    else printf("NO"); //or print NO


    return 0;
}
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
Juzles
  • 19
  • 6
  • 2
    I'd focus more on improving your algorithm. I feel like its probable there is some number theory principle you can use to turn this into an iteration instead of a recursion. It may also just call for Dynamic Programming, which I wish I understood better myself. – Daniel Dec 18 '14 at 21:45
  • @Galvanic Is it to find c with multiples of a and b or is it whether c is in the ascension of a sequence of a, b, a+b, a+a+b, a+a+b+b, a+a+a+b+b, etc.? – George Houpis Dec 18 '14 at 22:10
  • @George Houpis, no it's not n x a + m x b, this question has been asked recently as tree recursion but I can't yet find it. – Weather Vane Dec 18 '14 at 22:19
  • The problem with the previous same question, was not how to solve it, but how to prevent it running out of stack space. – Weather Vane Dec 18 '14 at 22:26
  • 1
    @Galvanic Previous question: http://stackoverflow.com/questions/27335684/recursion-that-branches-running-out-of-memory/27336342#27336342 – Weather Vane Dec 18 '14 at 22:40
  • @WeatherVane In fact that is the same task but I dont really see a solution yet... – Juzles Dec 18 '14 at 23:56
  • @GeorgeHoupis it is in the ascension of a sequence like you wrote there, it is kind of like search through a tree and find the right branch – Juzles Dec 18 '14 at 23:57
  • @Galvanic I've provided a hint in the comment section of the other thread. – user3386109 Dec 19 '14 at 00:23
  • Is there an error in the tree picture in the other thread? (3,11) should be (3,10) right? – George Houpis Dec 19 '14 at 00:23
  • @GeorgeHoupis - yes, that's an error. – hatchet - done with SOverflow Dec 19 '14 at 00:27
  • In that other thread, the problem is solved already. I have to write iteration, recursion obv. fails to do it's job – Juzles Dec 19 '14 at 00:36
  • @Galvanic - I don't think the problem is really solved in that question. A really good solution hasn't been posted to either question, and a really good solution solves both questions. – hatchet - done with SOverflow Dec 19 '14 at 00:59
  • [How to find solutions of linear Diophantine ax + by = c?](http://math.stackexchange.com/questions/20717/how-to-find-solutions-of-linear-diophantine-ax-by-c) – ryanpattison Dec 19 '14 at 04:15

3 Answers3

0

My code below does its job well for low numbers

It doesn't. Try input 2 2 3. The most obvious error is:

In function 'main':
 warning: format '%I64d' expects type 'int *', but argument 2 has type 'long long int *'
 warning: format '%I64d' expects type 'int *', but argument 3 has type 'long long int *'
 warning: format '%I64d' expects type 'int *', but argument 4 has type 'long long int *'

To correct it, replace %I64d with %Ld.

but I think I'm loosing the battle with the bigger numbers...

Of course your recursive solution can make the stack overflow; for a program that demands less stack space, see this answer.

Community
  • 1
  • 1
Armali
  • 18,255
  • 14
  • 57
  • 171
-1

Perhaps I am not understanding the problem correctly, but here are two different iterative approaches. Maybe this could help you along:

#include <stdio.h>

int old_task( long a, long b, long c )
{
   size_t iteration;
   long left = a, right = b;
   for( iteration = 0; ( left < c ) && ( right < c ); ++iteration )
   {
      printf( "NOT %ld: %ld, %ld < %ld\n", iteration, left, right, c );
      if( iteration % 2 )
         left += right;
      else
         right += left;
   }
   printf( "STOP %ld: %ld, %ld < %ld\n", iteration, left, right, c );
   return ( ( left == c ) || ( right == c ) ) ? 1 : 0;
}

int task( long a, long b, long c )
{
    long f;
    /*long i = 0;*/
    for( f = a; f < c; f+= a )
    {
        /*printf( "Checking: %li * %li + %li * %li == %li\n", a, ++i, b, ( c - f ) / b, c );*/
        if( ( c - f ) % b == 0 )
            return 1;
    }
    return 0;
}

int main()
{
   long a,b,c;
   scanf("%ld %ld %ld",&a,&b,&c); //scaning

   printf( "%s\n\n", task( a, b, c ) ? "YES" : "NO" );
   return 0;
}
George Houpis
  • 1,729
  • 1
  • 9
  • 5
  • Why the -1? Please explain. – George Houpis Dec 18 '14 at 22:51
  • I explained in the above comments. – Weather Vane Dec 18 '14 at 22:54
  • "What I need help is, I need it to work better, and faster, and I don't know how to optimise it more." If very explicitly asking for HOW to optimize. I didn't think that would warrant a down vote though... – George Houpis Dec 18 '14 at 22:55
  • My iterative answer to the previous question I linked above, although voted +1 was incorrect, as was pointed out to me. It needs an optimized recursive solution. The answer from JS1 was much better, so feel free to downvote me there please. – Weather Vane Dec 18 '14 at 23:04
  • The problem you linked has a different description to the problem than this poorly worded one. But how is this not an n * a + m * b = c problem? – George Houpis Dec 18 '14 at 23:23
  • 1
    As far as I read, they are the same, even the limit 10^18, the same homework. A comment to my incorrect iterative answer there was "Now, a=5, b=6, c=22 returns YES, but there is no way of reaching 22, so the answer should be NO. –JS1." – Weather Vane Dec 18 '14 at 23:30
  • 1
    @GeorgeHoupis - as an example (I think), if a=4 and b=10, you can't get to 42. 3*a + 3*b is unreachable. Some combinations are unreachable because of the constraint of choosing adding a to b or b to a. It's not the same as choosing arbitrary values of m and n. – hatchet - done with SOverflow Dec 18 '14 at 23:35
  • Ah, ok. I see what you mean now. – George Houpis Dec 18 '14 at 23:37
  • @GeorgeHoupis The point I missed was that a or b change with each operation. You can see that in this OP example. That's why not m x a + n x b. – Weather Vane Dec 18 '14 at 23:39
-1

I think it can be solved with linear algebra. Let's say you've got a = 3, b = 4 and c = 15. So what you're looking for is

3x + 4y = 15
x = (15-4y) / 3

So if you divide it with 3 it should have no remainder. And I think here comes linear algebra, because 15-4y should be 0 modulo 3.

It's just an idea.

Bence Gedai
  • 1,461
  • 2
  • 13
  • 25