Fatoração de Fibonacci

21

Números de Fibonacci

Números de Fibonacci começar com f(1) = 1e f(2) = 1(alguns inclui f(0) = 0mas isso é irrelevante para este desafio. Então, para n > 2, f(n) = f(n-1) + f(n-2).

O desafio

Sua tarefa é encontrar e ngerar o -ésimo número positivo que pode ser expresso como produto dos números de Fibonacci. Você pode optar por torná-lo indexado em 0 ou 1, o que melhor lhe convier, mas você deve especificar isso em sua resposta.

Além disso, sua resposta deve calcular o 100º termo em um tempo razoável.

Casos de teste

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

Referências

Freira Furada
fonte
No caso de teste, por que alguns deles são n = resultado, enquanto para 7 e acima eles não são iguais. Talvez eu não entenda a pergunta. Mas eu só quero verificar
george
11
7não pode ser expresso como o produto dos números de Fibonacci. Portanto, o primeiro 1número necessário é 1, o 2nd é 2, ..., o 6th é 6, mas o 7th é 8.
Leaky Nun
Ah, claro, isso faz sentido
george
Você deve imprimir todas as maneiras de criar um número. Por exemplo 16 tem duas maneiras, ou você pode apenas produzir uma?
george
3
@george Eu acredito que o " corresponding product" é apenas para esclarecimento. Seu código precisa apenas gerar o " result".
Trichoplax

Respostas:

6

Geléia , 26 24 23 21 bytes

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

Experimente online!

Como 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
fonte
2
Qual é a complexidade desse algoritmo, em termos de entrada?
Leaky Nun
De qualquer forma, é muito rápido! Menos de 2 segundos para o 100-th prazo
Luis Mendo
@LeakyNun Não tenho idéia de como calcular isso, mas vendo como a entrada 400 leva 32 vezes mais que a entrada 100, eu diria que é exponencial. Lida com 100 com facilidade embora.
Dennis
11
Bem, só você sabe o que seu algoritmo é ...
Leaky Nun
Consegui torná-lo muito mais rápido, não recalculando a sequência de Fibonacci para cada número testado. Vou adicionar uma explicação assim que terminar de jogar golfe.
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

Experimente online!

fundo

Em Problemas e soluções avançados, H-187: Fibonacci é um quadrado , o proponente mostra que

Identidade de Fibonacci / Lucas

em que L n indica o n th número Lucas , e que - por outro lado - se

inverso Identidade Fibonacci / Lucas

então n é um número de Fibonacci e m é um número de Lucas.

Como funciona

Definimos o operador binário <|para nossos propósitos. Ele é indefinido nas versões recentes do Julia, mas ainda é reconhecido como operador pelo analisador.

Quando chamado com apenas um argumento ( n ), <|inicializa k como 1 . Enquanto n é positivo, subtrai ! K ( 1 se k é um produto dos números de Fibonacci, 0 se não) de n e se chama recursivamente, aumenta k em 1 . Quando n atingir 0 , a quantidade desejada de produtos foi encontrada, <|retornando o valor anterior de k , ou seja, ~ -k = k - 1 .

O operador unário !, redefinido como um teste para produtos com número de Fibonacci, realiza sua tarefa da seguinte maneira.

  • Se k = 1 , k é um produto dos números de Fibonacci. Nesse caso, aumentamos o valor de retorno any(...)para a potência ~ -k = k - 1 = 0 , então o resultado será 1 .

  • Se k> 1 , o resultado será o valor de any(....), que retornará true se e somente se o predicado √(5i^2+[4,-4])%1∋k%i<!(k÷i)retornar true para algum número inteiro i, de modo que 2 ≤ i ≤ k .

    As condições encadeadas no predicado retêm se k%ipertencem √(5i^2+[4,-4])%1e k%isão menores que !(k÷i).

    • √(5i^2+[4,-4])%1toma a raiz quadrada de 5i 2 + 4 e 5i 2 - 4 e calcula seus resíduos módulo 1 . Cada módulo é 0 se o número correspondente for um quadrado perfeito e um número positivo menor que 1 caso contrário.

      Como k%iretorna um número inteiro, ele só pode pertencer à matriz de módulos se k% i = 0 (ou seja, k é divisível por i ) e pelo menos um entre 5i 2 + 4 e 5i 2 - 4 é um quadrado perfeito (ou seja, i é um número de Fibonacci).

    • !(k÷i)recursivamente chama 1 com o argumento k ÷ i (divisão inteira), que será maior que 0 se e somente se k ÷ i for um produto dos números de Fibonacci.

Por indução ! tem a propriedade desejada.

Dennis
fonte
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)

A principal função ggera o kproduto Fibonacci, indexado em 1. Ele calcula g(100)que 315quase que instantaneamente. Isso ocorre com uma receita recursiva geral de contagem de números, nprocurando kinstâncias que satisfazem a função f. Cada uma dessas instâncias diminui a contagem necessária katé atingir 0.

A função auxiliar ftesta um número por ser um produto de Fibonacci. Ele gera recursivamente os números de Fibonacci em seus argumentos opcionais ae b. Emite "yes" se qualquer um dos seguintes for verdadeiro:

  • n<2. Isso implica n==1, o produto trivial)
  • n%a<f(n/a). Isso requer n%a==0e f(n/a)==True, ou seja, né um múltiplo do número de Fibonacci a, e a remoção desse fator aainda produz um produto de Fibonacci.
  • n-a>0<f(n,b,a+b), equivalente a n>a and f(n,b,a+b). Verifica se o número atual de Fibonacci sendo testado não é pelo menos ne se existe um número maior de Fibonacci. Agradecemos a Dennis por salvar 2 bytes usando o curto-circuito da desigualdade em vez de and.

A função gpode ser um byte mais curto quanto

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

se g(k)é sempre no máximo k*k, o que não tenho certeza é assintoticamente verdadeiro. Um limite de 2**kbasta, mas depois g(100)leva muito tempo. Talvez, em vez disso, o recursivo de gpossa ser feito f.

xnor
fonte
De acordo com esta tabela no OEIS, g(k)excede k*kquando k = 47000e acima.
Isaacg 18/11
2

Perl 6 ,  95  93 bytes

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

(Índice baseado em 0)

Teste:

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;
}

Explicação:

{
  (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
fonte
2

Python 3, 175 170 148 bytes

Graças 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)

Pega a entrada de STDIN e imprime em STDOUT. Este é um indexado. A computação do 100º termo leva aproximadamente um décimo de segundo.

Como 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

Experimente no Ideone

TheBikingViking
fonte
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

Teste em Ideone .

Como funciona

Inicializamos F como a tupla (2, 3) (os dois primeiros números de Fibonacci maiores que 1 ), k como 0 e n como um número inteiro lido em STDIN.

Enquanto n é positivo, fazemos o seguinte:

  • Acrescentar o próximo número de Fibonacci, calculado como F [k] + F [-1] , isto é, a soma dos dois últimos elementos de F para o tuplo F .

  • Incremento k .

  • Subtraia g (k) de n .

g retorna 1 , se e somente se k é um produto de números de Fibonacci, assim uma vez que n atinge 0 , k é o n th número de Fibonacci e imprimi-lo para stdOut.

g atinge seu objetivo da seguinte maneira.

  • Se k for 1 , é um produto dos números de Fibonacci e 1/kgarante que retornemos 1 .

  • Se k é maior que 1 , que chamamos g(k/i)de forma recursiva para todos os números de Fibonacci i em F .

    g(k/i)testa recursivamente se k / i é um produto com número de Fibonacci. Se g(k/i)retornar 1 e i dividir k uniformemente, k% i = 0 e a condição for k%i<g(k/i)mantida, então g retornará 1 se e somente se houver um número de Fibonacci tal que k seja o produto desse número de Fibonacci e outro produto dos números de Fibonacci.

Dennis
fonte
1

JavaScript (ES6), 136

É bem lento assim, calculando o termo 100 em cerca de 8 segundos no meu 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 golfe e mais rápido também (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
}

Teste

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
fonte
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!!)

Muito preguiçoso, muito infinito!

Possivelmente não da forma mais curta, mas eu tive que tentar essa abordagem, uma generalização de um método bastante conhecido para calcular a lista de números hamming. fé a lista de números de fibonacci a partir de 2. Por uma questão de brevidade, digamos que um lol (lista de listas) é uma lista infinita de listas infinitas ordenadas, ordenadas pelos seus primeiros elementos. mé uma função para mesclar um lol, removendo duplicatas. Ele usa duas funções auxiliares de infix. ?insere uma lista classificada infinita em um lol. #remove um valor de um lol que pode aparecer como cabeçalho das primeiras listas, reinserindo a lista restante com ?.

Finalmente, lé a lista de números que são produtos de números de fibonacci, definida como 1, seguida pela mesclagem de todas as listas obtidas pela multiplicação lpor um número de fibonacci. A última linha indica a função necessária (como de costume, sem vinculá-la a um nome, portanto, não a copie como está) usando !!para indexar na lista, o que torna a função indexada em 0.

Não há problema em calcular o número 100 ou 100.000.

Peneiradores cristãos
fonte
1

Casca , 13 bytes

Observe que Husk é mais novo que esse desafio. No entanto, ele e a função mais útil para este golfe ( Ξ) não foram criados com esse desafio em mente.

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

Experimente online!

Versão mais eficiente para 14 bytes:

Experimente online!

H.PWiz
fonte
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

Teste em Ideone .

Dennis
fonte