Факторизація Фібоначчі


21

Числа Фібоначчі

Числа Фібоначчі починаються з f(1) = 1і f(2) = 1(деякі входять , f(0) = 0але це не має ніякого відношення до цієї проблеми. Тоді для n > 2, f(n) = f(n-1) + f(n-2).

Змагання

Ваше завдання - знайти і вивести число n-позитивне число, яке можна виразити як добуток чисел Фібоначчі. Ви можете зробити його 0-індексованим або 1-індексованим, що підходить вам краще, але ви повинні вказати це у своїй відповіді.

Крім того, ваша відповідь повинна обчислити 100-й термін у розумні строки.

Тестові шафи

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

Список літератури


У тестовому випадку чомусь з них n = результат, тоді як для 7 і вище вони не рівні. Можливо, я не розумію питання. Але я просто хочу перевірити
Джордж

1
7не може бути виражена як добуток чисел Фібоначчі. Отже, 1необхідне число st 1, є 2nd 2, ..., 6th є 6, але 7th є 8.
Лина монашка

Ну звичайно, це має сенс
Джордж

Чи слід надрукувати всі способи виготовлення номера. Наприклад, 16 має два способи, або ви можете просто вивести один?
Джордж

3
@george Я вважаю, що " corresponding product" - це лише для уточнення. Ваш код потребує лише виведення " result".
трихоплакс

Відповіді:


6

Желе , 26 24 23 21 байт

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

Спробуйте в Інтернеті!

Як це працює

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
Яка складність цього алгоритму з точки зору введення?
Leaky Nun

У будь-якому випадку, це дуже швидко! Менше 2 секунд на 100-й термін
Луїс Мендо

@LeakyNun Я не маю уявлення, як це обчислити, але, бачачи, як вхід 400 займає в 32 рази більше часу, ніж вхід 100, я б сказав, що це експоненціальне. Однак, обробляйте 100 легко.
Денніс

1
Ну, ви тільки знаєте, який ваш алгоритм ...
Leaky Nun

Мені вдалося зробити це набагато швидше, не перерахувавши послідовність Фібоначчі для кожного перевіреного числа. Я додам пояснення, як тільки закінчу гольф.
Денніс

5

Джулія, 79 байт

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

Спробуйте в Інтернеті!

Фон

У « Розширених проблемах та рішеннях» H-187: Фібоначчі - це квадрат ;

Ідентичність Фібоначча / Лукаса

де L n позначає n- е число Лукаса , а що - навпаки - якщо

конвертувати ідентичність Фібоначчі / Лукаса

тоді n - число Фібоначчі, а m - число Лукаса.

Як це працює

Ми визначаємо двійковий оператор <|для наших цілей. Він не визначений в останніх версіях Джулії, але все ще визнаний парсером як оператор.

Коли викликається лише одним аргументом ( n ), <|ініціалізує k як 1 . Поки n позитивний, він віднімає ! K ( 1, якщо k - добуток чисел Фібоначчі, 0, якщо ні) з n і рекурсивно називає себе, з кроком k на 1 . Як тільки n досягне 0 , потрібна кількість продуктів знайдена, тому <|повертає попереднє значення k , тобто ~ -k = k - 1 .

Одинарний оператор !, переосмислений як тест для продуктів числа Фібоначчі, виконує своє завдання наступним чином.

  • Якщо k = 1 , k - добуток чисел Фібоначчі. У цьому випадку ми піднімаємо повернене значення any(...)до потужності ~ -k = k - 1 = 0 , тому результат буде 1 .

  • Якщо k> 1 , результатом буде значення any(....), яке повернеться істинним тоді і тільки тоді, коли предикат √(5i^2+[4,-4])%1∋k%i<!(k÷i)повертає істинне для деякого цілого числа i таке, що 2 ≤ i ≤ k .

    Приковані умови в предикаті утримуються, якщо k%iналежить √(5i^2+[4,-4])%1і k%iменше, ніж !(k÷i).

    • √(5i^2+[4,-4])%1бере квадратний корінь 5i 2 + 4 і 5i 2 - 4 і обчислює їх залишки за модулем 1 . Кожен модуль дорівнює 0, якщо відповідне число є досконалим квадратом, а додатне число менше 1, інакше.

      Оскільки k%iповертає ціле число, воно може належати до масиву модулів лише тоді, коли k% i = 0 (тобто k ділиться на i ) і принаймні одне серед 5i 2 + 4 і 5i 2 - 4 є досконалим квадратом (тобто, i число Фібоначчі).

    • !(k÷i)рекурсивно викликає 1 з аргументом k ÷ i (ціле ділення), який буде більшим за 0, якщо і лише тоді, коли k ÷ i - добуток чисел Фібоначчі.

За індукції ! має бажану властивість.


5

Пітон, 90 байт

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)

Основна функція gвиводить k1-й індексований продукт Фібоначчі. Він обчислюється g(100)як 315майже миттєво. Це іде так із загальним рекурсивним рецептом підрахунку чисел у nпошуках kекземплярів, які задовольняють функцію f. Кожен такий екземпляр знижує необхідну кількість, kпоки не досягне 0.

Допоміжна функція fперевіряє число на предмет продукту Фібоначчі. Він рекурсивно генерує числа Фібоначчі у своїх необов'язкових аргументах aта b. Він видає "так", якщо відповідає дійсності щось з наступного:

  • n<2. Це означає n==1, тривіальний продукт)
  • n%a<f(n/a). Це вимагає n%a==0і f(n/a)==True, тобто nкратно числу Фібоначчі a, і усунення цього фактора aще вихід продукту Фібоначчі.
  • n-a>0<f(n,b,a+b), що еквівалентно n>a and f(n,b,a+b). Перевіряє, що поточне число тестування Фібоначчі щонайменше не працює n, і деяке більше число Фібоначчі працює. Завдяки Деннісу за 2 економії байтів, використовуючи коротке замикання нерівності замість and.

Функція gможе бути на один байт коротше

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

якщо g(k)завжди максимум k*k, що я не впевнений, це асимптотично вірно. Обмежень 2**kвистачає, але потім g(100)забирає занадто багато часу. Можливо, замість цього gможна зробити рекурсивність f.


Згідно з цією таблицею в OEIS, g(k)перевищує k*kколи k = 47000і вище.
isaacg

2

Perl 6 ,  95  93 байт

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

(0 на основі індексу)

Тест:

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

Пояснення:

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

Пітон 3, 175 170 148 байт

Завдяки @Dennis на -22 байти

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)

Здійснює вхід зі STDIN та друкує на STDOUT. Це одноіндексований. Обчислення 100-го терміну займає приблизно десяту частину секунди.

Як це працює

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

Спробуйте це на Ideone


2

Python 2, 120 107 байт

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

Перевірте це на Ideone .

Як це працює

Ми ініціалізуємо F як кортеж (2, 3) (перші два числа Фібоначчі більше 1 ), k як 0 і n як ціле число, прочитане з STDIN.

Хоча n є позитивним, ми робимо наступне:

  • Дозапис наступне число Фібоначчі, обчислюється як F [K] + Ж [-1] , тобто, сума двох останніх елементів F до кортежу F .

  • Приріст k .

  • Віднімаємо g (k) від n .

g повертає 1, якщо і лише тоді, коли k є добутком чисел Фібоначчі, тож коли n досягає 0 , k - n- е число Фібоначчі, і ми друкуємо його до STDOUT.

g досягає своєї мети наступним чином.

  • Якщо k дорівнює 1 , це добуток чисел Фібоначчі і 1/kгарантує повернення 1 .

  • Якщо до більше ніж 1 , ми називаємо g(k/i)рекурсивно для всіх чисел Фібоначчі I в F .

    g(k/i)рекурсивно перевіряє, чи k / i - добуток числа Фібоначчі. Якщо g(k/i)повернення 1 і i ділить k рівномірно, k% i = 0 і умова k%i<g(k/i)виконується, то g поверне 1, якщо і тільки якщо є число Фібоначчі, таке, що k є добутком цього числа Фібоначчі та іншого добутку чисел Фібоначчі.


1

JavaScript (ES6), 136

Досить повільно гольфували таким чином, обчислюючи термін 100 приблизно за 8 секунд на моєму ПК.

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

Менше гольфу і швидше (уникати 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
}

Тест

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 байти

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

Дуже ледачий, набагато нескінченний!

Можливо, це не короткий шлях, але мені довелося спробувати цей підхід, узагальнення досить відомого методу для обчислення списку чисел чисел. f- це список номерів полів, починаючи з 2. Для стислості скажемо, що lol (список списків) - це нескінченний список упорядкованих нескінченних списків, упорядкованих за їх першими елементами. mце функція для злиття lol, видалення дублікатів. Він використовує дві допоміжні функції інфікування. ?вставляє нескінченний відсортований список у lol #видаляє значення з lol, яке може відображатися як голова перших списків, повторно вставляючи список, що залишився ?.

Нарешті, lперелік чисел, які є продуктами чисел у фіг., Визначається як 1 з подальшим злиттям усіх списків, отриманих шляхом множення lна число поля . Останній рядок констатує необхідну функцію (як звичайно, не прив'язуючи її до імені, тому не копіюйте її так, як є), використовуючи !!для індексації до списку, що робить функцію 0-індексованою.

Немає проблем з обчисленням 100-го чи 100-тисячного числа.



0

Python 2, 129 128 125 123 121 байт

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

Перевірте це на Ideone .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.