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


21

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

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

Соревнование

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

Кроме того, ваш ответ должен вычислить сотый срок за разумное время.

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

Ссылки


В тестовом примере почему некоторые из них n = результат, тогда как для 7 и выше они не равны. Может быть, я не понимаю вопроса. Но я просто хочу проверить
— Джордж

1
7не может быть выражено как произведение чисел Фибоначчи. Следовательно, 1первое требуемое число - это 1, 2есть 2, ..., 6есть 6, но 7есть 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
Какова сложность этого алгоритма с точки зрения ввода?
— Утренняя монахиня

В любом случае, это очень быстро! Менее чем за 2 секунды на сотый срок
— Луис Мендо

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

1
Ну, только вы знаете, каков ваш алгоритм ...
— Leaky Nun

Мне удалось сделать это намного быстрее, не пересчитывая последовательность Фибоначчи для каждого проверенного числа. Я добавлю объяснение, как только я закончу играть в гольф.
— Деннис

5

Юлия, 79 байт

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

Попробуйте онлайн!

Задний план

В « Продвинутых задачах и решениях» H-187: Фибоначчи - это квадрат , предлагающий показывает, что

Личность Фибоначчи / Лукаса

где L n обозначает n- е число Лукаса , и это - наоборот - если

обратная личность Фибоначчи / Лукаса

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

Как это устроено

Мы определяем бинарный оператор <|для наших целей. Он не определен в последних версиях Julia, но все еще распознается синтаксическим анализатором как оператор.

Когда вызывается только с одним аргументом ( 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(....), которое будет возвращать true тогда и только тогда, когда предикат √(5i^2+[4,-4])%1∋k%i<!(k÷i)возвращает true для некоторого целого числа 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 является идеальным квадратом (т. Е. я - число Фибоначчи).

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

По индукции ,! имеет желаемое свойство.


5

Python, 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выводит произведение kФибоначчи, 1-индексированное. Это вычисляется 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]

if g(k)всегда самое большее k*k, что я не уверен, асимптотически верно. Границы 2**kдостаточно, но тогда она g(100)занимает слишком много времени. Может быть, вместо этого gможно сделать рекурсивный из f.


Согласно этой таблице в OEIS, g(k)превышает, k*kкогда k = 47000и выше.
— Исаак

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

Python 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 .

  • Инкремент к .

  • Вычтите g (k) из n .

g возвращает 1 тогда и только тогда, когда k является произведением чисел Фибоначчи, поэтому, когда n достигает 0 , k является n- м числом Фибоначчи, и мы печатаем его в STDOUT.

г достигает своей цели следующим образом.

  • Если 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, которое может появиться в качестве заголовка первых списков, повторно вставляя оставшийся список с помощью ?.

Наконец, 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.