Faktorisasi Fibonacci


21

Angka Fibonacci

Bilangan Fibonacci mulai dengan f(1) = 1dan f(2) = 1(beberapa termasuk f(0) = 0tapi ini tidak relevan dengan tantangan ini. Kemudian, untuk n > 2, f(n) = f(n-1) + f(n-2).

Tantangan

Tugas Anda adalah untuk menemukan dan menampilkan angka npositif -th yang dapat dinyatakan sebagai produk angka Fibonacci. Anda dapat memilih untuk membuatnya 0-diindeks atau 1-diindeks, mana yang lebih cocok untuk Anda, tetapi Anda harus menentukan ini dalam jawaban Anda.

Juga, jawaban Anda harus menghitung istilah ke-100 dalam waktu yang wajar.

Testcases

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

Referensi


Dalam kasus uji mengapa beberapa dari mereka n = hasil, sedangkan untuk 7 dan di atas mereka tidak sama. Mungkin saya tidak mengerti pertanyaannya. Tapi saya hanya ingin memeriksa
george

1
7tidak dapat dinyatakan sebagai produk angka Fibonacci. Oleh karena itu, angka yang 1diperlukan adalah 1, 2nd adalah 2, ..., yang 6ke - i 6, tetapi 7ke - i 8.
Leaky Nun

Ah tentu saja, itu masuk akal
george

Jika Anda mencetak semua cara dalam membuat nomor. Misalnya 16 memiliki dua cara, atau dapatkah Anda hanya menghasilkan satu?
george

3
@george Saya percaya " corresponding product" hanya untuk klarifikasi. Kode Anda hanya perlu menampilkan " result".
trichoplax

Jawaban:


6

Jelly , 26 24 23 21 byte

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

Cobalah online!

Bagaimana itu bekerja

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.

2
Apa kompleksitas dari algoritma ini, dalam hal input?
Leaky Nun

Bagaimanapun, ini sangat cepat! Kurang dari 2 detik untuk masa ke-100
Luis Mendo

@ LeakyNun Saya tidak tahu bagaimana menghitung itu, tetapi melihat bagaimana input 400 membutuhkan 32 kali lebih lama dari input 100, saya akan mengatakan itu eksponensial. Menangani 100 dengan mudah sekalipun.
Dennis

1
Nah, hanya Anda yang tahu apa algoritme Anda ...
Leaky Nun

Saya berhasil membuatnya jauh lebih cepat dengan tidak menghitung ulang deret Fibonacci untuk setiap angka yang diuji. Saya akan menambahkan penjelasan begitu saya selesai bermain golf.
Dennis

5

Julia, 79 byte

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

Cobalah online!

Latar Belakang

Dalam Advanced Problem and Solutions, H-187: Fibonacci adalah kuadrat , pengusul menunjukkan hal itu

Identitas Fibonacci / Lucas

di mana L n menunjukkan nomor Lucas ke- n , dan itu - sebaliknya - jika

Converse Fibonacci / Lucas identity

maka n adalah angka Fibonacci dan m adalah angka Lucas.

Bagaimana itu bekerja

Kami mendefinisikan operator biner <|untuk tujuan kami. Ini tidak terdefinisi dalam versi terbaru Julia, tetapi masih diakui sebagai operator oleh parser.

Saat dipanggil hanya dengan satu argumen ( n ), <|inisialisasi k sebagai 1 . Sementara n adalah positif, ia mengurangkan ! K ( 1 jika k adalah produk dari angka-angka Fibonacci, 0 jika tidak) dari n dan secara rekursif menyebut dirinya sendiri, menambah k sebesar 1 . Setelah n mencapai 0 , jumlah produk yang diinginkan telah ditemukan, jadi <|kembalikan nilai k sebelumnya , yaitu, ~ -k = k - 1 .

Operator unary !, didefinisikan ulang sebagai tes untuk produk angka Fibonacci, mencapai tugasnya sebagai berikut.

  • Jika k = 1 , k adalah produk angka Fibonacci. Dalam hal ini, kami menaikkan nilai kembali any(...)ke daya ~ -k = k - 1 = 0 , sehingga hasilnya adalah 1 .

  • Jika k> 1 , hasilnya akan menjadi nilai any(....), yang akan mengembalikan true jika dan hanya jika predikat √(5i^2+[4,-4])%1∋k%i<!(k÷i)mengembalikan true untuk beberapa integer i sedemikian rupa sehingga 2 ≤ i ≤ k .

    Kondisi dirantai dalam pegangan predikat jika k%imilik √(5i^2+[4,-4])%1dan k%ikurang dari !(k÷i).

    • √(5i^2+[4,-4])%1mengambil akar kuadrat dari 5i 2 + 4 dan 5i 2 - 4 dan menghitung residu modulo 1 mereka . Setiap modulus adalah 0 jika angka yang sesuai adalah kuadrat sempurna, dan angka positif kurang dari 1 sebaliknya.

      Karena k%imengembalikan bilangan bulat, itu hanya dapat menjadi milik array moduli jika k% i = 0 (yaitu, k dapat dibagi oleh i ) dan setidaknya satu di antara 5i 2 + 4 dan 5i 2 - 4 adalah kuadrat sempurna (yaitu, i adalah angka Fibonacci).

    • !(k÷i)secara rekursif memanggil 1 dengan argumen k ÷ i (divisi integer), yang akan lebih besar dari 0 jika dan hanya jika k ÷ i adalah produk dari angka Fibonacci.

Dengan induksi, ! memiliki properti yang diinginkan.


5

Python, 90 byte

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)

Fungsi utama gmenampilkan kproduk Fibonacci, yang diindeks 1. Ini menghitung g(100)sebagai 315hampir seketika. Itu berjalan begitu dengan resep rekursif umum menghitung angka nmencari kcontoh yang memenuhi fungsi f. Setiap instance tersebut menurunkan jumlah yang diperlukan khingga mencapai 0.

Fungsi tambahan fmenguji angka untuk menjadi produk Fibonacci. Secara rekursif menghasilkan angka-angka Fibonacci dalam argumen opsional adan b. Ini menampilkan "ya" jika salah satu dari yang berikut ini benar:

  • n<2. Ini menyiratkan n==1, produk sepele)
  • n%a<f(n/a). Ini memerlukan n%a==0dan f(n/a)==True, yaitu, yang nmerupakan kelipatan dari angka Fibonacci a, dan menghilangkan faktor ini amasih menghasilkan produk Fibonacci.
  • n-a>0<f(n,b,a+b), setara dengan n>a and f(n,b,a+b). Memeriksa bahwa nomor Fibonacci saat ini sedang diuji tidak setidaknya n, dan beberapa angka Fibonacci yang lebih besar berfungsi. Terima kasih kepada Dennis untuk menghemat 2 byte menggunakan hubung singkat ketimpangan and.

Fungsi ini gbisa lebih pendek satu byte

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

jika g(k)selalu paling banyak k*k, yang saya tidak yakin secara asimptotik benar. Sebuah terikat dari 2**kmencukupi, tapi kemudian g(100)membutuhkan waktu terlalu lama. Mungkin sebaliknya rekursif gdapat dilakukan di f.


Menurut tabel ini di OEIS, g(k)melebihi k*kkapan k = 47000dan di atas.
isaacg

2

Perl 6 ,  95  93 byte

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

(0 indeks berbasis)

Uji:

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

Penjelasan:

{
  (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
}

2

Python 3, 175 170 148 byte

Berkat @ Dennis untuk -22 byte

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)

Mengambil input dari STDIN dan mencetak ke STDOUT. Ini satu-diindeks. Menghitung jangka waktu ke-100 kira-kira membutuhkan sepersepuluh detik.

Bagaimana itu bekerja

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

Cobalah di Ideone


2

Python 2, 120 107 byte

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

Uji di Ideone .

Bagaimana itu bekerja

Kami menginisialisasi F sebagai tuple (2, 3) (dua angka Fibonacci pertama lebih besar dari 1 ), k sebagai 0 dan n sebagai bilangan bulat yang dibaca dari STDIN.

Sementara n adalah positif, kami melakukan hal berikut:

  • Tambah jumlah Fibonacci berikutnya, dihitung sebagai F [k] + F [-1] , yaitu, jumlah dari dua elemen terakhir dari F ke tupel F .

  • Peningkatan k .

  • Kurangi g (k) dari n .

g mengembalikan 1 jika dan hanya jika k adalah produk dari angka Fibonacci, jadi begitu n mencapai 0 , k adalah angka Fibonacci ke- n dan kami mencetaknya ke STDOUT.

g mencapai tujuannya sebagai berikut.

  • Jika k adalah 1 , ini adalah produk dari angka Fibonacci, dan 1/kpastikan kami mengembalikan 1 .

  • Jika k lebih besar dari 1 , kita sebut g(k/i)rekursif untuk semua nomor Fibonacci saya di F .

    g(k/i)secara rekursif menguji apakah k / i adalah produk angka Fibonacci. Jika g(k/i)pengembalian 1 dan i membagi k secara merata, k% i = 0 dan syarat k%i<g(k/i)berlaku, maka g akan mengembalikan 1 jika dan hanya jika ada bilangan Fibonacci sehingga k adalah produk dari bilangan Fibonacci dan produk lain dari bilangan Fibonacci.


1

JavaScript (ES6), 136

Cukup lambat bermain golf dengan cara ini, istilah komputasi 100 dalam waktu sekitar 8 detik di PC saya.

(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')

Kurang golf dan lebih cepat juga (menghindari 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
}

Uji

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>


1

Haskell, 123 byte

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

Sangat malas, tidak terbatas!

Mungkin bukan jalan pintas, tetapi saya harus mencoba pendekatan ini, generalisasi dari metode yang cukup terkenal untuk menghitung daftar nomor palu. fadalah daftar angka fibonacci mulai dari 2. Untuk singkatnya, katakanlah bahwa lol (daftar daftar) adalah daftar tak terbatas dari daftar tak terbatas yang diurutkan, diurutkan berdasarkan elemen pertama mereka. madalah fungsi untuk menggabungkan lol, menghapus duplikat. Ia menggunakan dua fungsi pembantu infiks. ?menyisipkan daftar diurutkan tak terbatas ke dalam lol. #menghapus nilai dari lol yang mungkin muncul sebagai kepala daftar pertama, memasukkan kembali daftar yang tersisa ?.

Akhirnya, ladalah daftar angka yang merupakan produk dari angka fibonacci, didefinisikan sebagai 1 diikuti oleh gabungan dari semua daftar yang diperoleh dengan mengalikannya ldengan nomor fibonacci. Baris terakhir menyatakan fungsi yang diperlukan (seperti biasa tanpa mengikatnya ke nama, jadi jangan salin apa adanya) menggunakan !!untuk mengindeks ke dalam daftar, yang membuat fungsi 0-diindeks.

Tidak ada masalah menghitung angka 100 atau 100.000.


1

Sekam , 13 byte

Perhatikan bahwa Husk lebih baru dari tantangan ini. Namun itu dan fungsi yang paling berguna untuk golf ini ( Ξ) tidak dibuat dengan tantangan ini.

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

Cobalah online!

Versi yang lebih efisien untuk 14 byte:

Cobalah online!


0

Python 2, 129 128 125 123 121 byte

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

Uji di Ideone .

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.