Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Background

The 1-2-3-Tribonacci Sequence

Imagine for a second that you could make a fibonacci sequence by replacing the standard iteration formula with the following:

tribonacci

Basically, instead of summing the last two to get the next, you sum the last three. This is the basis for the 1-2-3-Tribonacci sequence.

Brown's Criterion

Brown's Criterion state that you may represent any integer value as a sum of members of a sequence provided that:

  1. x sub n equals 1

  2. For all n greater than 1, x sub n less than 2 x sub n - 1

What this means for the challenge

You may describe any positive integer as a sum of members of the 1-2-3-Tribonacci sequence formed by the following initial conditions:

initial conditions

This is known as, for every value in this sequence, the ratio between terms is never greater than 2 (the ratio averages out at about 1.839).

How to write in this numerical representation system

Let's say that you use a little-endian representation. Line up members of the sequence like so:

1  2  3  6 11 20 37 68

Then, you take your number to be represented (for our tests, let's say it's 63) and find the values of the given 1-2-3-Tribonacci which sum to 63 (using the largest values first!). If the number is part of the sum, put a 1 under it, 0 if not.

1  2  3  6 11 20 37 68
0  0  0  1  0  1  1  0

You may do this for any given integer - just verify that you use the largest values below your given input first!

Definition (finally)

Write a program or function that will do the following given some positive integer input n (written in any standard base) between 1 and your language's maximum value:

  1. Convert the value into the defined 1-2-3-Tribonacci's numerical representation.
  2. Using this binary-like representation, and read it as if it were binary. This means that the digits stay the same, but what they mean changes.
  3. Take this binary number and convert it into the base of the original number.
  4. Output or return this new number.

However, as long as the output is valid, you needn't follow these steps. If you magically find some formula that is shorter (and mathematically equivalent), feel free to use it.

Examples

Let the function f be the function described by the definition, and let [] represent steps taken (as little-endian, though it shouldn't matter) (you do not need to follow this process, this is just the process described):

>>> f(1)
[1]
[1]
[1]
1

>>> f(5)
[5]
[0, 1, 1]
[6]
6

>>> f(63)
[63]
[0, 0, 0, 1, 0, 1, 1]
[104]
104
share|improve this question
2  
Could you change the sequence to 1, 1, 2, ... for the purposes of this challenge? This is what's commonly known as the tribonacci sequence, your starting numbers are not. – orlp 18 hours ago
    
@orlp I will rename the challenge to 1-2-3-trib specific – VoteToClose 18 hours ago
3  
The base thing seems weird. If we take input in base 2, we can skip step 3. – Dennis 18 hours ago
2  
In the interest of clarity, that might be better. If it were my challenge, I'd skip steps 2 and 3 altogether. They seem an unrelated tack-on to the core challenge which add nothing and will make some approaches that much harder. – Dennis 18 hours ago
2  
@LliwTelracs Maybe just add it as an addendum to your existing post then. – Jonathan Allan 17 hours ago

10 Answers 10

Javascript 117 111 bytes

Thanks to @theonlygusti for helping golf off 5 bytes

x=>{r=0;a=[1,2,3];i=1;while(a[++i]<x)a[i+1]=a[i]+a[i-1]+a[i-2];for(;x;i--)if(x>=a[i]){r+=1<<i;x-=a[i]}return r}

How It Works

First, the function generates all tribonacci numbers until it finds one greater than the input

a=[1,2,3];i=1;for(;a[++i]<x;)a[i+1]=a[i]+a[i-1]+a[i-2];

Next, it reverse searches the list of numbers. If a number is less than the input, it adds 2^(index of that number) to the return value and reduces the input by that number.

for(;x;i--)if(x>=a[i]){r+=1<<i;x-=a[i]}

Finally it returns the result.

Try it Online

share|improve this answer
    
what about a[++i]<x inside the for condition to save a byte? – theonlygusti 18 hours ago
    
Also, you can replace x>0 with x. Save another 2 bytes. – theonlygusti 18 hours ago
    
That's a pretty good algorithm. o.o – VoteToClose 18 hours ago

Python 2, 110 102 bytes

-3 bytes thanks to Rod (neat trick for casting boolean i to an int with +i so the repr `+i` works)

n=input()
x=[3,2,1]
r=''
while x[0]<n:x=[sum(x[:3])]+x
for v in x:i=n>=v;n-=v*i;r+=`+i`
print int(r,2)

Try it online!

share|improve this answer
    
you can replace '01'[i] with `+i` – Rod 17 hours ago
    
i is a boolean not an int. Edit - Ohhh +i, neat. – Jonathan Allan 17 hours ago
1  
@Rod Is that trick in the Python 2 tips and tricks? – VoteToClose 17 hours ago
    
@VoteToClose I don't think so – Rod 17 hours ago

JavaScript (ES6), 97 93 bytes

Here, we are using reduce() on a recursive function. We assume that the output is 31-bit (which is the largest unsigned quantity that JS can easily work with for bitwise operations anyway).

n=>[...Array(x=31)].reduce(p=>(c=(F=k=>k<4?k:F(--k)+F(--k)+F(--k))(x--))>n?p:(n-=c,p|1<<x),0)

Performance wise, this is clearly not very efficient.

For the curious:

  • The ratio between the number of calls to F() for N+1 reduce() iterations vs N iterations quickly converges towards the Tribonacci Constant (≈ 1.83929). Therefore, each additional bit in the output costs approximately twice as much time as the previous one.
  • With 31 bits, the F() function is called a good 124 million times.

Test

NB: This may take 1 or 2 seconds to complete.

let f =

n=>[...Array(x=31)].reduce(p=>(c=(F=k=>k<4?k:F(--k)+F(--k)+F(--k))(x--))>n?p:(n-=c,p|1<<x),0)

console.log(f(63))

share|improve this answer
    
Wow, that lags my browser when I use it. xD – VoteToClose 17 hours ago
    
@VoteToClose Performance wise, this is dreadfully inefficient. :-) The test code should not lag for too long, though. On my box, I get about 600ms in Firefox and 900ms in Chrome. Is it much slower on your side? – Arnauld 17 hours ago
    
Like, 5 seconds. xD – VoteToClose 16 hours ago
    
@VoteToClose Should be a bit faster now. The 32nd iteration was pointless, so I've limited the output to an unsigned 31-bit integer. – Arnauld 16 hours ago

Mathematica, 78 74 bytes

Fold[#+##&,#~NumberDecompose~Reverse@LinearRecurrence[{1,1,1},{1,2,3},#]]&

LinearRecurrence[{1,1,1},{1,2,3},#] generates a list, of length equal to the input, of the 1-2-3 tribonacci numbers. (The {1,1,1} represents the sum of the previous three terms, while {1,2,3} are the initial values.) Then #~NumberDecompose~ finds the greediest way to write the input as a sum of elements of the list (this is the same function that would decompose a monetary amount into multiples of the available currencies, for example). Finally, Fold[#+##&,...] converts the resulting binary list into a (base-10) integer.

Previous submission:

Fold[#+##&,#~NumberDecompose~Reverse@Array[If[#<4,#,Tr[#0/@(#-Range@3)]]&,#]]&

As is often the case (though not above), this golfed version is super slow on inputs larger than 20 or so, because it generates (with non-optimized recursion) a list of tribs whose length is the input; replacing the final # by a more reasonable bound like Round[2Log@#+1] results in much better performance.

share|improve this answer
    
Whaat? Mathematica doesn't have an 123Tribonacci[] builtin? – palsch 11 hours ago
1  
Not exactly, although it turns out that using a builtin does help a bit. – Greg Martin 11 hours ago

Haskell, 95 bytes

(a!b)c=a:(b!c)(a+b+c)
e#(r,c)|c-e<0=(2*r,c)|1<2=(2*r+1,c-e)
f n=fst$foldr(#)(0,n)$take n$(1!2)3

Usage example: f 63 -> 104. Try it online!.

How it works: ! builds the 1-2-3-Tribonacci sequence. Given 1, 2 and 3 as the start parameters, we take the first n elements of the sequence. Then we fold from the right function # which subtracts the next element e from n and sets the bit in the return value r if e is needed or lets the bit unset. Setting the bit is doubling r and adding 1, letting it unset is just doubling.

share|improve this answer

Jelly, 31 bytes

S=³
3RUµḣ3S;µ<³Ạµ¿µŒPÇÐfṀe@ЀµḄ

Try it online!

I'm almost certain there is a MUCH shorter way to achieve this in Jelly.

How?

S=³ - Link 1, compare sum to input: list
S   - sum
  ³ - 3rd command line argument which is 1st program argument.
 =  - equal?

3RUµḣ3S;µ<³Ạµ¿µŒPÇÐfṀe@ЀµḄ - Main link: n
3RU                         - range(3) upended -> [3,2,1]
   µ    µ   µ¿              - while
         <³                 - less than input (vectorises)
           Ạ                - all?
    ḣ3S;                    -     head(3), sum, and concatenate
                                  [3,2,1] -> [6,3,2,1] -> [11,6,3,2,1] -> ...
              µ             - monadic chain separation, call the result x
               ŒP           - power set of x - e.g. for [6,3,2,1] -> [[],[6],[3],[2],[1],[6,3],[6,2],[6,1],[3,2],[3,1],[2,1],[6,3,2],[6,3,1],[6,2,1],[3,2,1],[6,3,2,1]]
                  Ðf        - filter keep
                 Ç          -     last link (1) as a monad (those that sum to the input)
                    Ṁ       - maximum (e.g. an input of 63 would yield [[37,20,6],[37,20,3,2,1]], the maximum of which is [37,20,6], the one with the largest numbers used)
                         µ  - monadic chain separation (to have x as the right argument below)
                     e@Ѐ   - exists in with reversed arguments mapped over x (e.g. [37,20,6] with x = [68,37,20,11,6,3,2,1] yields [0,1,1,0,1,0,0,0])
                          Ḅ - convert from binary to integer.        
share|improve this answer

Perl 6, 93 91 bytes

-2 bytes thanks to b2gills

{my@f=1,2,3,*+*+*...*>$^n;sum @f».&{$_~~any first *.sum==$n,@f.combinations}Z*(2 X**^∞)}

How it works

  • First, it generates the 1-2-3-Tribonacci sequence up to the first element larger than the input:

    my @f = 1, 2, 3, *+*+* ... * > $^n;
  • Based on that it finds the subset of the sequence which adds up to the input:

    first *.sum==$n, @f.combinations
  • Based on that it constructs a list of booleans specifying whether each element of the sequence is part of the sum:

    @f».&{$_~~any ...}
  • And finally it interprets that list of True=1, False=0 values as base 2 and returns it as a (base 10) number:

    sum ... Z* (2 X** ^∞)
share|improve this answer
1  
You can shorten it by using *>$^n and .sum==$n. Also the space isn't needed between my and @f – Brad Gilbert b2gills 11 hours ago

JavaScript (ES6), 61 60 bytes

n=>(g=(x,y,z)=>(n>x&&g(y,z,x+y+z)*2)+!(n<x||![n-=x]))(1,2,3)

Calculates the 1-2-3-Tribonacci numbers until it reaches the original number, then as the recursion unwinds, tries to subtract each one in turn, doubling the result as it goes.

Edit: Saved 1 byte thanks to @Arnauld.

share|improve this answer
    
Wow! Very nice. Could n=>(g=(x,y,z)=>(n>x&&g(y,z,x+y+z)*2)+!(n<x||![n-=x]))(1,2,3) save a byte? – Arnauld 10 hours ago
    
@Arnauld I had been looking for something using n<x|| but that ![] is just genius. – Neil 9 hours ago

Batch, 151 148 145 bytes

@set/ar=0,n=%1
@call:c 3 2 1
@echo %r%
@exit/b
:c
@set/as=%1+%2+%3
@if %n% gtr %3 call:c %s% %*
@set/ar*=2
@if %n% geq %3 set/an-=%3,r+=1

Port of my JavaScript answer. Edit: Saved 3 bytes by passing my subroutine arguments in reverse order and another 3 bytes by using individual @s on each line instead of @echo off.

share|improve this answer

Jelly (fork), 17 bytes

3RṚµḣ3S;µ³¡
æF¢ṪḄ

This relies on a fork of Jelly where I am disappointingly still working on implementing an efficient Frobenius solve atom. For those who are interested, I would like to match Mathematica's speed in FrobeniusSolve and luckily there is an explanation of their method in the paper "Making Change and Finding Repfigits: Balancing a Knapsack" by Daniel Lichtblau.

Explanation

3RṚµḣ3S;µ³¡  Helper link. Nilad - no arguments
3            The constant 3
 R           Range. Makes [1, 2, 3]
  Ṛ          Reverse. Makes [3, 2, 1]
   µ         Begin new monadic chain operating on [3, 2, 1]
        µ    Create monadic chain
    ḣ3         Take the first 3 items
      S        Sum
       ;       Prepend to the list
         ³¡  Repeat it n (initial argument from main) times

æF¢ṪḄ        Main link. Input: integer n
  ¢          Call helper link as a nilad
æF           Frobenius solve for n using the first n 123-Tribonacci values in reverse
   Ṫ         Tail. Take the last value. The results of Frobenius solve are ordered
             where the last result uses the least
    Ḅ        Unbinary. Convert digits from base 2 to base 10
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.