Factorisation de Fibonacci

21

Numéros de Fibonacci

Les nombres de Fibonacci commencent par f(1) = 1et f(2) = 1(certains comprennent , f(0) = 0mais cela n'a aucune importance à ce défi. Ensuite, pour n > 2, f(n) = f(n-1) + f(n-2).

Le défi

Votre tâche consiste à trouver et à sortir le n-ième nombre positif qui peut être exprimé en tant que produits des nombres de Fibonacci. Vous pouvez choisir de le rendre indexé 0 ou 1, selon ce qui vous convient le mieux, mais vous devez le spécifier dans votre réponse.

De plus, votre réponse doit calculer le 100e terme dans un délai raisonnable.

Cas de test

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

Les références

Leaky Nun
la source
Dans le cas test, pourquoi certains d'entre eux n = résultat, alors que pour 7 et plus, ils ne sont pas égaux. Peut-être que je ne comprends pas la question. Mais je veux juste vérifier
George
1
7ne peut pas être exprimé comme le produit des nombres de Fibonacci. Par conséquent, le 1st nombre requis est 1, le 2nd est 2, ..., le 6th est 6, mais le 7th est 8.
Leaky Nun
Ah bien sûr, cela a du sens
George
Devez-vous imprimer toutes les façons de faire un nombre. Par exemple, 16 a deux manières, ou pouvez-vous simplement en sortir une?
George
3
@george Je crois que le " corresponding product" est juste pour clarification. Votre code n'a besoin que de sortir le " result".
trichoplax

Réponses:

6

Gelée , 26 24 23 21 octets

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

Essayez-le en ligne!

Comment ça marche

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
la source
2
Quelle est la complexité de cet algorithme, en termes d'entrée?
Leaky Nun
En tout cas, c'est très rapide! Moins de 2 secondes pour le 100 e mandat
Luis Mendo
@LeakyNun Je n'ai aucune idée de comment calculer cela, mais vu comment l'entrée 400 prend 32 fois plus de temps que l'entrée 100, je dirais que c'est exponentiel. Manipule 100 avec facilité cependant.
Dennis
1
Eh bien, vous seul savez quel est votre algorithme ...
Leaky Nun
J'ai réussi à le rendre beaucoup plus rapide en ne recalculant pas la séquence de Fibonacci pour chaque numéro testé. J'ajouterai une explication dès que j'aurai fini de jouer au golf.
Dennis
5

Julia, 79 octets

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

Essayez-le en ligne!

Contexte

Dans Advanced Problems and Solutions, H-187: Fibonacci est un carré , le proposant montre que

Identité Fibonacci / Lucas

L n désigne le n ème nombre de Lucas , et que - inversement - si

converse identité Fibonacci / Lucas

alors n est un nombre de Fibonacci et m est un nombre de Lucas.

Comment ça marche

Nous définissons l'opérateur binaire <|pour nos besoins. Il n'est pas défini dans les versions récentes de Julia, mais est toujours reconnu comme opérateur par l'analyseur.

Lorsqu'il est appelé avec un seul argument ( n ), <|initialise k comme 1 . Alors que n est positif, il soustrait ! K ( 1 si k est un produit des nombres de Fibonacci, 0 sinon) de n et s'appelle récursivement, incrémente k de 1 . Une fois que n atteint 0 , la quantité souhaitée de produits a été trouvée, <|renvoie donc la valeur précédente de k , c'est-à-dire ~ -k = k - 1 .

L'opérateur unaire !, redéfini comme un test pour les produits de nombres de Fibonacci, accomplit sa tâche comme suit.

  • Si k = 1 , k est un produit des nombres de Fibonacci. Dans ce cas, nous élevons la valeur de retour de any(...)à la puissance ~ -k = k - 1 = 0 , le résultat sera donc 1 .

  • Si k> 1 , le résultat sera la valeur de any(....), qui retournera vrai si et seulement si le prédicat √(5i^2+[4,-4])%1∋k%i<!(k÷i)retourne vrai pour un entier i tel que 2 ≤ i ≤ k .

    Les conditions chaînées dans le prédicat tiennent si elles k%iappartiennent à √(5i^2+[4,-4])%1et k%isont inférieures à !(k÷i).

    • √(5i^2+[4,-4])%1prend la racine carrée de 5i 2 + 4 et 5i 2 - 4 et calcule leurs résidus modulo 1 . Chaque module est 0 si le nombre correspondant est un carré parfait, et un nombre positif inférieur à 1 sinon.

      Puisque k%irenvoie un entier, il ne peut appartenir au tableau de modules que si k% i = 0 (c'est-à-dire que k est divisible par i ) et au moins un parmi 5i 2 + 4 et 5i 2 - 4 est un carré parfait (c'est-à-dire, i est un nombre de Fibonacci).

    • !(k÷i) appelle récursivement 1 avec l'argument k ÷ i (division entière), qui sera supérieur à 0 si et seulement si k ÷ i est un produit des nombres de Fibonacci.

Par induction ,! a la propriété souhaitée.

Dennis
la source
5

Python, 90 octets

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 fonction principale gaffiche le kproduit Fibonacci, indexé 1. Il calcule g(100)comme 315presque instantanément. Il en va de même avec une recette récursive générale de comptage des nombres à la nrecherche dek instances qui satisfont la fonction f. Chacune de ces instances réduit le nombre requis kjusqu'à ce qu'il atteigne 0.

La fonction auxiliaire fteste un certain nombre pour être un produit Fibonacci. Il génère récursivement les nombres de Fibonacci dans ses arguments optionnelsa et b. Il renvoie "oui" si l'une des conditions suivantes est vraie:

  • n<2. Cela implique n==1, le produit trivial)
  • n%a<f(n/a). Cela nécessite n%a==0et f(n/a)==True, c'est-à-dire qu'il ns'agit d'un multiple du nombre de Fibonacci a, et la suppression de ce facteur adonne toujours un produit Fibonacci.
  • n-a>0<f(n,b,a+b), équivalent à n>a and f(n,b,a+b). Vérifie que le nombre de Fibonacci en cours de test ne l'est pas au moins n, et qu'un nombre de Fibonacci supérieur fonctionne. Merci à Dennis pour 2 octets d'économie en utilisant le court-circuit d'inégalité au lieu de and.

La fonction gpeut être un octet plus courte car

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

si g(k)est toujours au plus k*k, ce qui, je ne suis pas sûr, est asymptotiquement vrai. Une limite de 2**ksuffit, mais g(100)prend trop de temps. Peut-être qu'au lieu de cela, la récursivité gpeut être effectuée f.

xnor
la source
Selon ce tableau à OEIS, g(k)dépasse k*kquand k = 47000et au-dessus.
isaacg
2

Perl 6 ,  95  93 octets

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

(Index basé sur 0)

Tester:

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

Explication:

{
  (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
la source
2

Python 3, 175 170 148 octets

Merci à @Dennis pour -22 octets

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)

Prend l'entrée de STDIN et imprime vers STDOUT. C'est un index. Le calcul du 100e terme prend environ un dixième de seconde.

Comment ça marche

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

Essayez-le sur Ideone

TheBikingViking
la source
2

Python 2, 120 107 octets

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

Testez-le sur Ideone .

Comment ça marche

Nous initialisons F comme le tuple (2, 3) (les deux premiers nombres de Fibonacci supérieurs à 1 ), k comme 0 et n comme un entier lu à partir de STDIN.

Alors que n est positif, nous faisons ce qui suit:

  • Ajouter le prochain nombre de Fibonacci, calculé comme F [k] + F [-1] , c'est-à-dire la somme des deux derniers éléments de F au tuple F .

  • Incrément k .

  • Soustrayez g (k) de n .

g renvoie 1 si et seulement si k est un produit des nombres de Fibonacci, donc une fois que n atteint 0 , k est le n ème nombre de Fibonacci et nous l'imprimons sur STDOUT.

g atteint son objectif comme suit.

  • Si k est 1 , c'est un produit des nombres de Fibonacci, et 1/ks'assure que nous retournons 1 .

  • Si k est supérieur à 1 , nous appelons g(k/i)récursivement tous les nombres de Fibonacci i dans F .

    g(k/i)teste récursivement si k / i est un produit de nombre de Fibonacci. Si g(k/i)renvoie 1 et i divise k également, k% i = 0 et la condition k%i<g(k/i)est vérifiée, donc g renverra 1 si et seulement s'il y a un nombre de Fibonacci tel que k est le produit de ce nombre de Fibonacci et un autre produit de nombres de Fibonacci.

Dennis
la source
1

JavaScript (ES6), 136

Golf assez lent de cette façon, calculant le terme 100 en environ 8 secondes sur mon 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')

Moins golfé et plus rapide aussi (éviter 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
}

Tester

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
la source
1

Haskell, 123 octets

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

Très paresseux, infini!

Ce n'est peut-être pas la manière la plus courte, mais j'ai dû essayer cette approche, une généralisation d'une méthode assez bien connue pour calculer la liste des nombres parasites. fest la liste des nombres de fibonacci à partir de 2. Par souci de concision, disons qu'un lol (liste de listes) est une liste infinie de listes infinies ordonnées, ordonnées par leurs premiers éléments. mest une fonction pour fusionner un lol, en supprimant les doublons. Il utilise deux fonctions d'assistance infixe. ?insère une liste triée infinie dans un lol. #supprime une valeur d'un lol qui peut apparaître en tête des premières listes, réinsérant la liste restante avec? .

Enfin, lest la liste des nombres qui sont des produits des nombres de fibonacci, définie comme 1 suivie de la fusion de toutes les listes obtenues en multipliant lpar un nombre de fibonacci. La dernière ligne indique la fonction requise (comme d'habitude sans la lier à un nom, donc ne la copiez pas telle quelle) en utilisant !!pour indexer dans la liste, ce qui rend la fonction indexée 0.

Il n'y a aucun problème à calculer le 100e ou 100 000e nombre.

Christian Sievers
la source
1

Husk , 13 octets

Notez que Husk est plus récent que ce défi. Cependant, il et la fonction la plus utile pour ce golf ( Ξ) n'ont pas été créés avec ce défi à l'esprit.

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

Essayez-le en ligne!

Version plus efficace pour 14 octets:

Essayez-le en ligne!

H.PWiz
la source
0

Python 2, 129 128 125 125 123 121 octets

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

Testez-le sur Ideone .

Dennis
la source