Factorización de Fibonacci

21

Números de Fibonacci

Los números de Fibonacci comienzan con f(1) = 1y f(2) = 1(algunos incluyen f(0) = 0, pero esto es irrelevante para este desafío. Entonces, para n > 2, f(n) = f(n-1) + f(n-2).

El reto

Su tarea es encontrar y generar el nenésimo número positivo que se puede expresar como productos de los números de Fibonacci. Puede elegir que sea indexado 0 o indexado, lo que más le convenga, pero debe especificar esto en su respuesta.

Además, su respuesta debe calcular el centésimo término en un tiempo razonable.

Casos de prueba

n   result corresponding product (for reference)
1   1      1
2   2      2
3   3      3
4   4      2*2
5   5      5
6   6      2*3
7   8      2*2*2 or 8
8   9      3*3
9   10     2*5
10  12     2*2*3
11  13     13
12  15     3*5
13  16     2*2*2*2 or 2*8
14  18     2*3*3
15  20     2*2*5
16  21     21
17  24     2*2*2*3 or 3*8
18  25     5*5
19  26     2*13
20  27     3*3*3
100 315    3*5*21

Referencias

Monja permeable
fuente
En el caso de prueba, ¿por qué algunos de ellos son n = resultado, mientras que para 7 o más no son iguales? Quizás no entiendo la pregunta. Pero solo quiero comprobarlo
george
1
7no se puede expresar como el producto de los números de Fibonacci. Por lo tanto, el 1número requerido de st es 1, el 2nd es 2, ..., el 6th es 6, pero el 7th es 8.
Leaky Nun
Ah, por supuesto, eso tiene sentido
George
Debe imprimir todas las formas de hacer un número. Por ejemplo, 16 tiene dos formas, ¿o puede simplemente generar una?
George
3
@george Creo que el " corresponding product" es solo para aclarar. Su código solo necesita generar el " result".
trichoplax

Respuestas:

6

Gelatina , 26 24 23 21 bytes

ÆDf÷߀FðḊ¡
1ç#2+С1¤Ṫ

Pruébalo en línea!

Cómo funciona

1ç#2+С1¤Ṫ  Main link. Argument: n (integer)

        ¤   Combine the three links to the left into a niladic chain.
   2          Set the left argument and the return value to 2 (third positive
              Fibonacci number).
       1      Yield 1 (second positive Fibonacci number).
    +С       Compute the sum of the return value and right argument, replacing the
              return value with the sum and the right argument with the previous
              return value.
              Do this n times, collecting all return values in a list.
              This returns A, the first n Fibonacci numbers greater than 1.
1             Set the return value to 1.
 ç#           Call the helper link with left argument k = 1, 2, 3... and right
              argument A = [2, 3, 5...] until n of them return a truthy value.
              Collect the matches in a list.
           Ṫ  Tail; extract the last (n-th) match.


ÆDf÷߀FðḊ¡    Helper link. Left argument: k. Right argument: A

        Ḋ     Dequeue; yield r := [2, ..., k].
       ð ¡    If r in non-empty, execute the chain to the left. Return k otherwise.
ÆD              Yield the positive divisors of k.
   ÷            Divide k by all Fibonacci numbers in A.
  f             Filter; keep divisors that belong to k÷A, i.e., all divisors
                d for which k÷d belongs to A.
    ߀          Recursively call the helper link for each kept divisor d, with left
                argument d and right argument A.
      F         Flatten the result, yielding a non-empty array iff any of the
                recursive calls yielded a non-empty array or a number.
                If the left argument is 1, the helper link returns 1, so the
                array will be non-empty if the consecutive divisions by Fibonacci
                numbers eventually produced a 1.
Dennis
fuente
2
¿Cuál es la complejidad de este algoritmo, en términos de la entrada?
Leaky Nun
En cualquier caso, ¡es muy rápido! Menos de 2 segundos para el término número 100
Luis Mendo
@LeakyNun No tengo idea de cómo calcular eso, pero viendo cómo la entrada 400 tarda 32 veces más que la entrada 100, diría que es exponencial. Sin embargo, maneja 100 con facilidad.
Dennis
1
Bueno, solo tú sabes cuál es tu algoritmo ...
Leaky Nun
Logré hacerlo mucho más rápido al no volver a calcular la secuencia de Fibonacci para cada número probado. Agregaré una explicación tan pronto como termine de jugar al golf.
Dennis
5

Julia, 79 bytes

!k=any(i->√(5i^2+[4,-4])%1k%i<!(k÷i),2:k)^~-k
<|(n,k=1)=n>0?n-!k<|-~k:~-k

Pruébalo en línea!

Fondo

En Problemas y soluciones avanzadas, H-187: Fibonacci es un cuadrado , el proponente muestra que

Identidad de Fibonacci / Lucas

donde L n denota el n º número Lucas , y que - por el contrario - si

conversar la identidad de Fibonacci / Lucas

entonces n es un número de Fibonacci ym es un número de Lucas.

Cómo funciona

Definimos el operador binario <|para nuestros propósitos. No está definido en las versiones recientes de Julia, pero el analizador aún lo reconoce como operador.

Cuando se llama con un solo argumento ( n ), <|inicializa k como 1 . Mientras que n es positivo, resta ! K ( 1 si k es un producto de los números de Fibonacci, 0 si no) de n y recursivamente se llama a sí mismo, incrementa k en 1 . Una vez que n alcanza 0 , se ha encontrado la cantidad deseada de productos, por lo que <|devuelve el valor anterior de k , es decir, ~ -k = k - 1 .

El operador unario !, redefinido como una prueba para productos de número de Fibonacci, logra su tarea de la siguiente manera.

  • Si k = 1 , k es un producto de los números de Fibonacci. En este caso, elevamos el valor de retorno de any(...)a la potencia ~ -k = k - 1 = 0 , por lo que el resultado será 1 .

  • Si k> 1 , el resultado será el valor de any(....), que devolverá verdadero si y solo si el predicado √(5i^2+[4,-4])%1∋k%i<!(k÷i)devuelve verdadero para algún entero i tal que 2 ≤ i ≤ k .

    Las condiciones encadenadas en el predicado se mantienen si k%ipertenece √(5i^2+[4,-4])%1y k%ies menor que !(k÷i).

    • √(5i^2+[4,-4])%1toma la raíz cuadrada de 5i 2 + 4 y 5i 2 - 4 y calcula sus residuos módulo 1 . Cada módulo es 0 si el número correspondiente es un cuadrado perfecto y, de lo contrario , un número positivo menor que 1 .

      Como k%idevuelve un número entero, solo puede pertenecer a la matriz de módulos si k% i = 0 (es decir, k es divisible por i ) y al menos uno entre 5i 2 + 4 y 5i 2 - 4 es un cuadrado perfecto (es decir, i es un número de Fibonacci).

    • !(k÷i)llama recursivamente a 1 con el argumento k ÷ i (división entera), que será mayor que 0 si y solo si k ÷ i es un producto de los números de Fibonacci.

Por inducción ,! Tiene la propiedad deseada.

Dennis
fuente
5

Python, 90 bytes

f=lambda n,a=2,b=3:n<2or n%a<f(n/a)or n-a>0<f(n,b,a+b)
g=lambda k,n=1:k and-~g(k-f(n),n+1)

La función principal ggenera el producto kth Fibonacci, 1 indexado. Calcula g(100)como 315casi al instante. Va así con una receta recursiva general de contar números nbuscando kinstancias que satisfagan la función f. Cada una de esas instancias reduce el recuento requerido khasta que alcanza 0.

La función auxiliar fprueba que un número sea un producto de Fibonacci. Genera recursivamente los números de Fibonacci en sus argumentos opcionales ay b. Produce "yes" si alguno de los siguientes es verdadero:

  • n<2. Esto implica n==1, el producto trivial)
  • n%a<f(n/a). Esto requiere n%a==0y f(n/a)==True, es decir, nes un múltiplo del número de Fibonacci a, y eliminar este factor atodavía produce un producto de Fibonacci.
  • n-a>0<f(n,b,a+b), equivalente a n>a and f(n,b,a+b). Comprueba que el número actual de Fibonacci que se está probando no es al menos n, y funciona un número mayor de Fibonacci. Gracias a Dennis por guardar 2 bytes usando el cortocircuito de desigualdad en lugar de and.

La función gpuede ser un byte más corta como

lambda k:filter(f,range(k*k+1))[k]

si g(k)siempre es a lo sumo k*k, lo que no estoy seguro es asintóticamente cierto. Un límite de 2**ksuficientes, pero luego g(100)lleva demasiado tiempo. Quizás en cambio el recursivo deg se pueda hacerf .

xnor
fuente
De acuerdo con esta tabla en OEIS, g(k)excede k*kcuándo k = 47000y más.
isaacg
2

Perl 6 ,  95  93 bytes

{(1..*).grep({$/=$_;map {->{$/%$_||($//=$_);$/}...*!%%$_;0},reverse 2,3,&[+]...*>$_;2>$/})[$_]}
{(1..*).grep({$/=$_;map {->{$/%$_||($//=$_);$/}...*%$_;0},reverse 2,3,&[+]...*>$_;2>$/})[$_]}

(Índice basado en 0)

Prueba:

my &fib-prod = {(1..*).grep({$/=$_;map {->{$/%$_||($//=$_);$/}...*%$_;0},reverse 2,3,&[+]...*>$_;2>$/})[$_]}

say fib-prod 0 ..^ 20;
# (1 2 3 4 5 6 8 9 10 12 13 15 16 18 20 21 24 25 26 27)
say time-this { say fib-prod 100 -1; };
# 315
# 1.05135779

sub time-this (&code) {
  my $start = now;
  code();
  now - $start;
}

Explicación:

{
  (1..*).grep(
    {
      $/ = $_; # copy the input ($_) to $/
      map { # map used just for side effect
        ->{
          $/ % $_    # if $/ is divisible by the current fib factor
        ||
          ($/ /= $_) # divide it out once
        ;
          # return the current value in $/
          $/
        }
        ... # repeat until that returns:
        * !%% $_ # something that is not divisible by the current fib factor
        ;0
      },
      # the possible fibonacci factors plus one, reversed
      # ( the extra is to save one byte )
      reverse 2,3,&[+] ... *>$_;

      # is the end result of factoring equal to 1
      # ( for the grep above )
      2 > $/
    }
  )[ $_ ] # get the value at 0-based index
}
Brad Gilbert b2gills
fuente
2

Python 3, 175 170 148 bytes

Gracias a @Dennis por -22 bytes

j=x=int(input())
y=1,1
exec('y+=y[-2]+y[-1],;'*x)
i=c=0
while c<x:
    if j>=x:j=0;i+=1;t=i
    if t%y[~j]<1:t/=y[~j];j-=1
    if t<2:c+=1;j=x
    j+=1
print(i)

Toma información de STDIN e imprime en STDOUT. Esto es un índice. Calcular el término 100 toma aproximadamente una décima de segundo.

Cómo funciona

j=x=int(input())                Get term number x from STDIN and set Fibonacci number index
                                j to x to force initialisation of j later 
y=1,1                           Initialise tuple y with start values for Fibonacci sequence
exec('y+=y[-2]+y[-1],;'*x)      Compute the Fibonacci sequence to x terms and store in y
i=c=0                           Initialise test number i and term counter c
while c<x:                      Loop until x th term is calculated
    if j>=x:j=0;i+=1;t=i        Initialise Fibonacci number index j, increment i and
                                initialise temp variable t for looping through all j for
                                some i. Executes during the first pass of the loop since
                                at this point, j=x
    if t%y[~j]<1:t/=y[~j];j-=1  Find t mod the j th largest Fibonacci number in y and if no
                                remainder, update t by dividing by this number.
                                Decrementing j means that after a later increment, no
                                change to j occurs, allowing for numbers that are 
                                divisible by the same Fibonacci number more than once by
                                testing again with the same j
    if t<2:c+=1;j=x             If repeated division by ever-smaller Fibonacci numbers
                                leaves 1, i must be a Fibonacci product and c is
                                incremented. Setting j equal to x causes j to be reset
                                to 0 during the next loop execution
    j+=1                        Increment j
print(i)                        i must now be the x th Fibonacci product. Print i to STDOUT

Pruébalo en Ideone

TheBikingViking
fuente
2

Python 2, 120 107 bytes

g=lambda k:1/k+any(k%i==0<g(k/i)for i in F)
F=2,3;k=0;n=input()
while n:F+=F[k]+F[-1],;k+=1;n-=g(k)
print k

Pruébalo en Ideone .

Cómo funciona

Inicializamos F como la tupla (2, 3) (la primera de dos número mayor Fibonacci que 1 ), k como 0 y n como un número entero lee de STDIN.

Si bien n es positivo, hacemos lo siguiente:

  • Anexar el siguiente número de Fibonacci, calculado como F [k] + F [-1] , es decir, la suma de los dos últimos elementos de F a la tupla F .

  • Incremento k .

  • Resta g (k) de n .

g devuelve 1 si y solo si k es un producto de números de Fibonacci, por lo que una vez que n alcanza 0 , k es el número n de Fibonacci y lo imprimimos en STDOUT.

g logra su propósito de la siguiente manera.

  • Si k es 1 , es un producto de los números de Fibonacci y 1/kse asegura de que devolvamos 1 .

  • Si k es mayor que 1 , que llamamos g(k/i)recursivamente para todos los números de Fibonacci i en F .

    g(k/i)prueba recursivamente si k / i es un producto con número de Fibonacci. Si g(k/i)devuelve 1 e i divide k uniformemente, k% i = 0 y la condición se k%i<g(k/i)cumple, entonces g devolverá 1 si y solo si hay un número de Fibonacci tal que k sea ​​el producto de ese número de Fibonacci y otro producto de los números de Fibonacci.

Dennis
fuente
1

JavaScript (ES6), 136

De esta manera, jugué bastante lento, calculando el término 100 en aproximadamente 8 segundos en mi PC.

(n,F=i=>i>1?F(i-1)+F(i-2):i+1,K=(n,i=1,d,x)=>eval('for(;(d=F(i++))<=n&&!(x=!(n%d)&&K(n/d)););x||n<2'))=>eval('for(a=0;n;)K(++a)&&--n;a')

Menos golf y más rápido también (evitando eval)

n=>{
  F=i=> i>1 ? F(i-1)+F(i-2) : i+1; // recursive calc Fibonacci number
  K=(n,i=1,d,x)=>{ // recursive check divisibility
    for(; (d=F(i++))<=n && !(x=!(n%d)&&K(n/d)); );
    return x||n<2
  };
  for(a=0; n; )
    K(++a) && --n;
  return a
}

Prueba

X=(n,F=i=>i>1?F(i-1)+F(i-2):i+1,K=(n,i=1,d,x)=>eval('for(;(d=F(i++))<=n&&!(x=!(n%d)&&K(n/d)););x||n<2'))=>eval('for(a=0;n;)K(++a)&&--n;a')

function test() {
  var i=+I.value
  O.textContent=X(i)
}

test()
<input id=I value=100 >
<button onclick="test()">Go</button><pre id=O></pre>

edc65
fuente
1

Haskell, 123 bytes

f=2:scanl(+)3f
m((a:b):c)=a:m(b?(a#c))
v#((a:b):c)|v==a=b?(v#c)
_#l=l
y?(z:e)|y>z=z:y?e
a?b=a:b
l=1:m[[a*b|b<-l]|a<-f]
(l!!)

Muy vago, mucho infinito!

Posiblemente no sea el camino más corto, pero tuve que probar este enfoque, una generalización de un método bastante conocido para calcular la lista de números de Hamming. fes la lista de números de Fibonacci a partir de 2. Por brevedad, digamos que un lol (lista de listas) es una lista infinita de listas infinitas ordenadas, ordenadas por sus primeros elementos. mes una función para fusionar un lol, eliminando duplicados. Utiliza dos funciones auxiliares infix. ?inserta una lista ordenada infinita en un lol. #elimina un valor de un lol que puede aparecer como encabezado de las primeras listas, reinsertando la lista restante con ?.

Finalmente, lestá la lista de números que son productos de números de Fibonacci, definidos como 1 seguidos de la fusión de todas las listas obtenidas al multiplicar lpor un número de Fibonacci. La última línea establece la función requerida (como de costumbre sin vincularla a un nombre, así que no la copie como está) usando !!para indexar en la lista, lo que hace que la función sea indexada en 0.

No hay problema para calcular el número 100 o 100,000.

Christian Sievers
fuente
1

Casco , 13 bytes

Tenga en cuenta que Husk es más nuevo que este desafío. Sin embargo, y la función más útil para este golf ( Ξ) no se crearon con este desafío en mente.

S!!Ṡ¡ȯuΞIṪ*İf

Pruébalo en línea!

Versión más eficiente para 14 bytes:

Pruébalo en línea!

H.PWiz
fuente
0

Python 2, 129 128 125 123 121 bytes

g=lambda k:1/k|any(abs(round(5**.5*i)**2-5*i*i)==4>k%i<g(k/i)for i in range(k+1))
f=lambda n,k=1:n and f(n-g(k),k+1)or~-k

Pruébalo en Ideone .

Dennis
fuente