6

For example:

5 = 1+1+1+1+1

5 = 1+1+1+2

5 = 1+1+2+1

5 = 1+2+1+1

5 = 2+1+1+1


5 = 1+2+2

5 = 2+2+1

5 = 2+1+2

Can anyone give a hint for a pseudo code on how this can be done please. Honestly have no clue how to even start. Also this looks like an exponential problem can it be done in linear time?

Thank you.

amanuel2
  • 4,508
  • 4
  • 36
  • 67
Phil15
  • 515
  • 5
  • 14
  • 4
    Looks like it might be the (n+1)th [Fibonacci number](https://en.wikipedia.org/wiki/Fibonacci_number)? – Peter de Rivaz Oct 15 '16 at 18:44
  • The solution is likely exponential to N, so I'm guessing no linear method is possible. – Captain Giraffe Oct 15 '16 at 18:45
  • 1
    Since its a fibonacci recurrence, so can be done in logarithmic time. – Shashwat Kumar Oct 15 '16 at 18:51
  • 1
    @CaptainGiraffe You'd be right if the question was to enumerate the ways. But it's not, it's asking to determine how many ways there are. This can be done without enumerating them. – pjs Oct 15 '16 at 18:54
  • @pjs Good call. – Captain Giraffe Oct 15 '16 at 18:55
  • I'm voting to close this question as off-topic because it belongs to Code Golf instead of Stackoverflow – Felipe Sabino Oct 15 '16 at 19:07
  • @FelipeSabino I don't know if you frequent Code Golf, but this clearly doesn't belong there. And even if it would be acceptable there, that wouldn't make it off-topic here. –  Oct 15 '16 at 19:23
  • @ShashwatKumat: that depends on you computational model. Since word sizes are generally small and the values grow exponentially, I'd think the number if word matter. That is, with the recurrence formula you have O(n log n) operations. The operations involve multiplication on O(n) sized values and these will take more than O(1), too. – Dietmar Kühl Oct 15 '16 at 19:40
  • @DietmarKühl: you know that there's a closed-form solution for F(n)... – lorro Oct 15 '16 at 22:22
  • @lorro: sure. You'll still need to write O(n) memory locations and have the involved operation operate on these entities! You'll still have some super-linear ckmpkexity! – Dietmar Kühl Oct 15 '16 at 22:25
  • How does a gimme-the-codes question with no work have 9 upvotes? – Barry Oct 16 '16 at 16:23
  • @DietmarKühl: why do you need to write O(n) locations? The question was the number of ways, not to list them. So you just calculate x1 = (1 + sqrt(5))/2; x2 = (1 - sqrt(5))/2; f = round( ((pow(x1, n) - pow(x2, n))/sqrt(5)); This works to a given (high) precision. We usually assume O(1) operations on POD types and inputs to fit those unless otherwise specified. – lorro Oct 17 '16 at 21:10
  • @lorro: for large values of `n` the `n`th Fibonacci number won't fit into a POD! The Big O analysis is only meaningful for large `n` as it is the behavior for `n` "converging" on infinity. – Dietmar Kühl Oct 17 '16 at 22:03
  • @DietmarKühl: then we have got different definitions. – lorro Oct 18 '16 at 07:36
  • @lorro: If your definition is different from the one I sketched I'd recommend you refresh your understanding, e.g., using the definition from [Wikipedia](https://en.m.wikipedia.org/wiki/Big_O_notation#/search) (that may bot be perfect but is at least close to the generally accepted definition). All I'm saying is that the computation using the closed formula is O(1) only if an infinite word size is assumed. If the word size is finite the result alone requires O(n) memory locations (due to the exponential growth of the result). – Dietmar Kühl Oct 18 '16 at 08:22
  • @DietmarKühl: 'O(1) only if an infinite word size is assumed' - that's precisely what we assume in theoretic calculations (RAM model) - then we choose an architecture in which word size is long enough for the longest allowed input. Granted, if you don't have long enough words then it's different, but - unless otherwise noted - we assume that you do. If you don't, then you need to specify encoding of I/O (strings? binary? unary?) and that's a whole different scenario. I don't see any references to bignums in OP's example. I'm aware that 128-bit can store up to F(186). – lorro Oct 19 '16 at 21:15

5 Answers5

6

In the example you have provided order of addends is important. (See the last two lines in your example). With this in mind, the answer seems to be related to Fibonacci numbers. Let's F(n) be the ways n can be written as 1s and 2s. Then the last addened is either 1 or 2. So F(n) = F(n-1) + F(n-2). These are the initial values:

F(1) = 1 (1 = 1)
F(2) = 2 (2 = 1 + 1, 2 = 2)
esam
  • 580
  • 3
  • 13
  • Thank you for your input, If I follow this logic I can get f(3) = f(2) + f(1) which is 3 that is correct if I check manually 3 = 2+1 , 3= 1+2 , 3 =1 + 1 +1 ... Now the bit which I do not understand is f(4) = f(3) + f(1) so f(3) we know from previous f(3)=3 and f(1) =1 so I thought the answer would be 4 but writing it out manually gives me 5 different ways. 4 = 1 + 1 + 1 +1 4 = 1 + 1 + 2 4 = 1 + 2 +1 4 = 2 + 1 +1 4 = 2 + 2 where am I making a mistake? – Phil15 Oct 16 '16 at 17:04
  • 1
    @Phil15 f(4) = f(3) + f(2) = 3 + 2 = 5 – esam Oct 16 '16 at 23:27
2

This is actually the (n+1)th Fibonacci number. Here's why:

Let's call f(n) the number of ways to represent n. If you have n, then you can represent it as (n-1)+1 or (n-2)+2. Thus the ways to represent it are the number of ways to represent it is f(n-1) + f(n-2). This is the same recurrence as the Fibonacci numbers. Furthermore, we see if n=1 then we have 1 way, and if n=2 then we have 2 ways. Thus the (n+1)th Fibonacci number is your answer. There are algorithms out there to compute enormous Fibonacci numbers very quickly.

kcborys
  • 316
  • 1
  • 11
  • Thanks for the answer, I can see now it is fib(n+1) but how did you figure it out, what if the questions was take 1 or 2 or 3 steps. so for f(3) -> fib(3+1) = fib(2+1) + fib(1 + 1) + fib(0 +1) .. but I do not understand why is Fibonacci applicable to this? – Phil15 Oct 16 '16 at 17:52
  • By this do you mean represent it as a sum of 1's, 2's, or also 3's? Then the problem would be more challenging. You should still be able to do it with a rather straight forward Dynamic Programming solution, but it wouldn't be as "nice" as computing a Fibonacci number. – kcborys Oct 17 '16 at 08:34
2

Permutations

If we want to know how many possible orderings there are in some set of size n without repetition (i.e., elements selected are removed from the available pool), the factorial of n (or n!) gives the answer:

double factorial(int n)
{
    if (n <= 0)
        return 1;
    else
        return n * factorial(n - 1);
}

Note: This also has an iterative solution and can even be approximated using the gamma function:

std::round(std::tgamma(n + 1)); // where n >= 0

The problem set starts with all 1s. Each time the set changes, two 1s are replaced by one 2. We want to find the number of ways k items (the 2s) can be arranged in a set of size n. We can query the number of possible permutations by computing:

double permutation(int n, int k)
{
    return factorial(n) / factorial(n - k);
}

However, this is not quite the result we want. The problem is, permutations consider ordering, e.g., the sequence 2,2,2 would count as six distinct variations.

Combinations

These are essentially permutations which ignore ordering. Since the order no longer matters, many permutations are redundant. Redundancy per permutation can be found by computing k!. Dividing the number of permutations by this value gives the number of combinations:

Note: This is known as the binomial coefficient and should be read as "n choose k."

double combination(int n, int k)
{
    return permutation(n, k) / factorial(k);
}

int solve(int n)
{
    double result = 0;

    if (n > 0) {
        for ( int k = 0; k <= n; k += 1, n -= 1 )
            result += combination(n, k);
    }
    return std::round(result);
}

This is a general solution. For example, if the problem were instead to find the number of ways an integer can be represented as a sum of 1s and 3s, we would only need to adjust the decrement of the set size (n-2) at each iteration.

Fibonacci numbers

The reason the solution using Fibonacci numbers works, has to do with their relation to the binomial coefficients. The binomial coefficients can be arranged to form Pascal's triangle, which when stored as a lower-triangular matrix, can be accessed using n and k as row/column indices to locate the element equal to combination(n,k).

The pattern of n and k as they change over the lifetime of solve, plot a diagonal when viewed as coordinates on a 2-D grid. The result of summing values along a diagonal of Pascal's triangle is a Fibonacci number. If the pattern changes (e.g., when finding sums of 1s and 3s), this will no longer be the case and this solution will fail.

Interestingly, Fibonacci numbers can be computed in constant time. Which means we can solve this problem in constant time simply by finding the (n+1)th Fibonacci number.

int fibonacci(int n)
{
    constexpr double SQRT_5 = std::sqrt(5.0);
    constexpr double GOLDEN_RATIO = (SQRT_5 + 1.0) / 2.0;

    return std::round(std::pow(GOLDEN_RATIO, n) / SQRT_5);
}

int solve(int n)
{
    if (n > 0)
        return fibonacci(n + 1);
    return 0;
}

As a final note, the numbers generated by both the factorial and fibonacci functions can be extremely large. Therefore, a large-maths library may be needed if n will be large.

John Q.
  • 177
  • 4
0

Here is the code using backtracking which solves your problem. At each step, while remembering the numbers used to get the sum so far(using vectors here), first make a copy of them, first subtract 1 from n and add it to the copy then recur with n-1 and the copy of the vector with 1 added to it and print when n==0. then return and repeat the same for 2, which essentially is backtracking.

#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;
int n;
void print(vector<int> vect){
    cout << n <<" = ";
    for(int i=0;i<vect.size(); ++i){
       if(i>0)
           cout <<"+" <<vect[i];
       else cout << vect[i];
    }
    cout << endl;
}

void gen(int n, vector<int> vect){
   if(!n)
      print(vect);
   else{
      for(int i=1;i<=2;++i){
          if(n-i>=0){
              std::vector<int> vect2(vect);
              vect2.push_back(i);
              gen(n-i,vect2);
          }
      }
   }
}

int main(){
   scanf("%d",&n);
   vector<int> vect;
   gen(n,vect);
}
yabhishek
  • 408
  • 4
  • 14
  • OP asked about the *number* of ways, not how to enumerate them. – Francisco Oct 15 '16 at 18:58
  • My bad..I looked at his example where he asks for pseudo code and then talks about the problem being exponential, so I thought probably he needs to enumerate them. – yabhishek Oct 15 '16 at 19:04
0

This problem can be easily visualized as follows:

Consider a frog, that is present in front of a stairway. It needs to reach the n-th stair, but he can only jump 1 or 2 steps on the stairway at a time. Find the number of ways in which he can reach the n-th stair?

Let T(n) denote the number of ways to reach the n-th stair.

So, T(1) = 1 and T(2) = 2(2 one-step jumps or 1 two-step jump, so 2 ways)

In order to reach the n-th stair, we already know the number of ways to reach the (n-1)th stair and the (n-2)th stair.

So, once can simple reach the n-th stair by a 1-step jump from (n-1)th stair or a 2-step jump from (n-2)th step...

Hence, T(n) = T(n-1) + T(n-2)

Hope it helps!!!

User_Targaryen
  • 4,125
  • 4
  • 30
  • 51