eolymp

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

   В XIII веке итальянский математик Леонардо Фибоначчи исследовал решение следующей задачи:

   Фермер выращивает кроликов. Когда кролик становится взрослым (ему исполняется два месяца), то каждый месяц он дает потомство в одного кролика. Сколько кроликов будет у фермера через n месяцев, если сначала у него был только один кролик (считается, что кролики не умирают и дают потомство по выше описанной схеме)?

   Очевидно, что в начале первого и второго месяца у фермера один кролик, поскольку потомства еще нет. На третий месяц будет два кролика. На четвертый месяц первый кролик даст еще одного, а второй потомства не даст, так как ему еще один месяц. Таким образом, на четвертый месяц будет три кролика.

medv_fib_01

   Количество кроликов в n - ый месяц будет равно количеству кроликов, которое было в (n – 1) - ом месяце, плюс количество родившихся. Последних будет столько, сколько кроликов дают потомство (которым уже исполнилось 2 месяца). Их число равно количеству кроликов в (n – 2) - ой месяц.

  Если через Fn обозначить количество кроликов после n - го месяца, то имеет место следующее рекуррентное соотношение:

Fn =  Fn-1 + Fn-2, F1 = F2 = 1

   Положим F0 = 0, при этом соотношение при n = 2 останется истинным. Таким образом образовалась последовательность

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ... ,

которая называется последовательностью Фибоначчи.

   Рассмотрим несколько функций f(n) вычисления n - го числа Фибоначчи. Для нахождения f(n) с линейной сложностью без запоминания значений f(1), f(2), …, f(n – 1) можно использовать циклический вариант:

int f(int n)

{

  int i, temp, a = 0, b = 1;

  for (i = 0; i < n; i++)

    temp = a, a = b, b = temp + a;

  return a;

}

   Максимальным числом Фибоначчи, которое помещается в тип int, является F46 = 1836311903. В 64-битовый целочисленный тип long long (__int64) помещается максимум F92. Если в задаче требуется находить значения f(n) для n > 92, то следует воспользоваться длинной арифметикой.

   В случае необходимости запоминания всех чисел Фибоначчи f(1), f(2), …, f(n), заведем массив m, в котором положим m[i] = f(i), 0 £ i £ n. Реализация может быть как циклическая, так и рекурсивная с запоминанием:

#include< stdio.h >

#include< memory.h >

int i, n, m[47];

void main(void)

{

  memset(m,0,sizeof(m));

  m[0] = 0; m[1] = 1;

  scanf("%d",&n);

  for (i = 2; i <= n; i++)

    m[i] = m[i-1] + m[i-2];

  while (scanf("%d",&i) == 1)

    printf("%d\n",m[i]);

}

#include< stdio.h >

#include< memory.h >

int i, n, m[47];

int f (int n)

{

  if (m[n] >= 0) return m[n];

  if (n == 0) return m[0] = 0;

  if (n == 1) return m[1] = 1;

  return m[n] = f(n-1) + f(n-2);

}

void main(void)

{

  memset(m,-1,sizeof(m));

  scanf("%d",&n); f(n);

  while(scanf("%d",&i) == 1)

  printf("%d\n",m[i]);

}

   При вычислении чисел Фибоначчи Fn для больших аргументов (n > 92) следует воспользоваться длинной арифметикой.

   Формула Бине выражает в явном виде значение Fn как функцию от n:

medv_fib_02

где medv_fib_03 – золотое сечение. При этом φ и  (-φ)-1 = 1 – φ являются корнями квадратного уравнения x2x – 1 = 0.

Следствие. При больших значениях n имеет место равенство: medv_fib_04. Следствие имеет место, так как с ростом n значение medv_fib_05 стремится к нулю.

   Наибольший общий делитель двух чисел Фибоначчи равен числу Фибоначчи с индексом, равным наибольшему общему делителю индексов, то есть

НОД(Fn, Fm) = FНОД(n,m)

   Следствие 1. Fm делится на Fn тогда и только тогда, когда m делится на n (за исключением n = 2). 

   Следствие 2. Fn может быть простым только для простых n (за исключением n = 4).

   1. Свойства чисел Фибоначчи. Доказать следующие свойства: 

   а) F0 + F1 + F2 + F3 + … +  Fn = Fn+2 – 1;

   б) F1 + F3 + F5 + … +  F2n-1 = F2n;

   в) F0 - F1 + F2 - F3 + … - F2n-1 +  F2n = F2n-1 – 1;

   г) F02 + F12 + F22 + F32 + … +  Fn2 = Fn * Fn+1;

   д) Fn+1Fn-1 – Fn2 = (-1)n (Равенство Ж. Д. Кассини);

   е) Fn+m = FmFn+1 + Fm-1 Fn;

   2. Лестница. Необходимо пройти по лестнице, состоящей из n ступенек. Из очередной ступеньки можно перейти или на следующую ступеньку, или перешагнуть через одну. Сколько существует вариантов прохождения лестницы?

   3. Кирпичная стена [Вальядолид, 900]. Высота кирпича равна 2, ширина – 1. Необходимо построить стену высоты 2 и длиной n. Сколькими способами можно это сделать в зависимости от значения n?

medv_fib_06

   4. Путь пчелы. Пчела начинает свой путь с клетки 1 или 2 и направляется в клетку с номером n. Двигаться пчеле можно только по соседним клеткам от меньшего номера к большему. Сколькими разными путями пчела может попасть в клетку с номером n?

medv_fib_07

   5. Новости по телефону.n друзей проживают в разных городах и разговаривают между собой только по телефону. Один телефонный звонок всегда длится одну минуту. Один из друзей желает поделиться новостью со всеми друзьями за наименьшее время. Найти наименьшее время, за которое все друзья будут знать новость, если каждый может совершить не более 2 звонков.

   6. AVL – деревья. Бинарное дерево называется AVL – деревом, если оно имеет следующие свойства:

  • высоты поддеревьев каждой вершины отличаются не более чем на единицу;
  • каждое поддерево для каждой вершины является AVL – деревом.

   Вычислить количество листьев в AVL – дереве высоты n.

   7. Резисторы. n одинаковых резисторов, с сопротивлением 1 Ом каждый, соединили как показано на рисунке (к первому резистору подсоединены резисторы с четными номерами последовательно, а с нечетными – параллельно). Найти сопротивление всей системы из n резисторов.

medv_fib_08

  8. Замораживание Фибоначчи [Вальядолид, 495]. Последовательность чисел Фибоначчи (0, 1, 1, 2, 3, 5, 8, 13, 21, ....) определяется рекуррентным соотношением:

f0 = 0, f1 = 1,

fi = fi-1 + fi-2, i ≥ 2

   Следует написать программу, которая вычисляет числа Фибоначчи.

   Вход. Каждая строка содержит целое неотрицательное число n (n £ 5000).

   Выход. Для каждого входного n вывести n - ое число Фибоначчи в соответствии с ниже приведенным форматом.

Пример входа

Пример выхода

5

The Fibonacci number for 5 is 5

7

The Fibonacci number for 7 is 13

11

The Fibonacci number for 11 is 89

9. Луч сквозь стекло  [Вальядолид, 10334]. Две пластины стекла совместили друг с другом. 
Сколькими способами an луч света может пройти сквозь пластины, если по пути он изменит направление n раз?

medv_fib_09

   Вход.Каждая строка содержит одно число n (0 ≤ n ≤ 1000).

   Выход. Для каждого теста вывести в отдельной строке значение an.

Пример входа

Пример выхода

0

1

1

2

2

3

   10. Шум мирового кубка  [Вальядолид, 10450]. По заданному числу n вычислить количество последовательностей из 0 и 1 длины n, в которых две единицы не стоят рядом.

   Вход. Первая строка содержит количество тестов. Каждая следующая строка является отдельным тестом и содержит число n (0 < n < 51).

   Выход. Для каждого теста вывести его номер и количество последовательностей из 0 и 1 длины n, в которых две единицы не стоят рядом.

Пример входа

Пример выхода

2

Scenario #1:

3

5

1

 

 

Scenario #2:

 

2

11. Числа Фибоначчи  [Вальядолид, 10579]. Числа Фибоначчи задаются рекуррентным соотношением:

f(1) = 1, f(2) = 1, f(n) = f(n – 1) + f(n – 2)

   Вход. Каждая строка содержит целое неотрицательное n.

   Выход. Для каждого входного n вывести n - ое число Фибоначчи (значение f(n)). Известно, что f(n) содержит не более 1000 знаков.

Пример входа

Пример выхода

3

2

100

354224848179261915075

   12. Пчела [Вальядолид, 11000]. В Африке живет специальный вид пчел. Каждый год самка производит на свет одного самца, а самец – самца и самку, после чего родители погибают. Ученые изобрели магическую самку пчелу, которая плодится как обыкновенная самка, но при этом является бессмертной. Необходимо вычислить число самцов и общее количество пчел в семействе, если изначально была лишь одна магическая самка пчела.

   Вход. Каждая строка содержит целое N (N ³ 0).Последний тест содержит N = -1 и не обрабатывается.

   Выход. Для каждого значения N вывести число самцов и общее количество пчел в семействе через N лет. Выводимые числа не более 232.

Пример входа

Пример выхода

1

1 2

3

4 7

-1

 

   13. Флаги [Тимус 1225]. Флаг состоит из n вертикальных полос белого, красного и синего цвета. Соседние полосы не могут иметь одинаковый цвет, а синяя полоса всегда должна находиться между красной и белой. Сколькими способами можно покрасить флаг из n полос?

   Вход. Число полос n (1 ≤ n ≤ 45) на флаге.

   Выход. Количество способов, которыми можно покрасить флаг из n полос.

Пример входа

Пример выхода

3

4

   14. Определитель. Вычислить определитель порядка n ´ n, где на главной диагонали и под ней стоят единицы, а над главной диагональю стоят минус единицы:

medv_fib_10

   15. Бесконечная сумма. Вычислить бесконечную сумму:

0.1 + 0.01 + 0.002 + 0.0003 + 0.00005 + 0.000008 + 0.0000013 + ...

 УКАЗАНИЯ И РЕШЕНИЯ

   1. Свойства чисел Фибоначчи. Доказательство всех равенств проводим по индукции.

а) База. n = 0. F0 = F2 – 1, что верно.

    Шаг. F1 + F2 + F3 + … +  Fn =  (F1 + F2 + F3 + … +  Fn-1) + Fn = Fn+1 – 1 + Fn = Fn+2 – 1.

б) База. n = 1. F1 = F2, что верно.

    Шаг. F1 + F3 + F5 + … +  F2n+1 = (F1 + F3 + F5 + … +  F2n-1) + F2n+1 =  F2n + F2n+1 = F2n+2.

в) База. n = 1. F0 – F1 + F2 = 0 – 1 + 1 = 0, F1 – 1  = 1 – 1 = 0.

    Шаг. (F0 – F1 + F2 – F3 + … – F2n-1 +  F2n) – F2n+1 +  F2n+2 =

F2n-1 – 1 – F2n+1 +  F2n+2 = F2n-1 - 1 – F2n+1 +  F2n + F2n+1 = F2n-1 +  F2n – 1 = F2n+1 – 1.

г) База. n = 0. F02 = F0 * F1, что верно.

    Шаг. F02+F12+ …+ Fn+12 =  (F02+F12+ …+ Fn2)+ Fn+12= Fn*Fn+1+Fn+12 = Fn+1*(Fn + Fn+1) = Fn+1*Fn+2.

д) Равенство получается из матричного тождества medv_fib_11 после вычисления определителей.

е) Индукция по m. База. m = 1. Fn+1 = F1Fn+1 + F0Fn =   1 * Fn+1 + 0 * Fn = Fn+1, что верно.

    Шаг. Fn+m+1 = Fn+m +  Fn+m-1 = FmFn+1 + Fm-1Fn + Fm-1 Fn+1 + Fm-2Fn =

 (Fm + Fm-1) Fn+1 + (Fm-1 + Fm-2) Fn = Fm+1 Fn+1 + FmFn.

   2. Лестница. Пусть f(n) – количество вариантов, которыми можно пройти по n ступенькам. С n - ой ступеньки можно перейти или на (n – 1) - ую, или на (n – 2) - ую. Количество вариантов пройти n ступенек равно количеству вариантов пройти n – 1 ступенек плюс количество вариантов пройти n – 2 ступеньки, то есть f(n) = f(n – 1) + f(n – 2). Очевидно, что f(1) = 1 и f(2) = 2. Таким образом f(n) является (n + 1)- ым числом Фибоначчи.

   3. Кирпичная стена [Вальядолид, 900]. Обозначим через f(n) количество способов, которыми можно построить кирпичную стену высоты 2 и длины n. Тогда можно положить один кирпич вертикально и далее строить стену длины n – 1 f(n – 1) способом, или положить два кирпича горизонтально и строить стену длины n – 2 f(n – 2) способами. То есть f(n) = f(n – 1) + f(n – 2). Также имеем: f(1) = 1 (один вертикальный кирпич), f(2) = 2 (два вертикальных или два горизонтальных кирпича). То есть f(n) является (n + 1) - ым числом Фибоначчи.

   4. Путь пчелы.  Из клетки с номером n пчела может попасть или в клетку с номером n + 1, или с номером n + 2. Задача сводится к движению по ступенькам лестницы. Количество разных путей до клетки с номером n равно Fn.

   5. Новости по телефону.  Звонки между друзьями следует организовать как показано на рисунке. Тогда на i - ой минуте о новости узнают еще Fi друзей. Наименьшее число минут, за которое новость распространится среди всех друзей, равно такому наименьшему значению k, для которого F1 + F2 + … + Fk ³ n (или то же самое что Fk+2 – 1 ³ n), где F1 = 1 (личность, которая распространяет новость) и F2 = 1 (друг, которому сделан первый звонок).

                  личность, распространяющая новость
                                    /------------^----\
      первая минута           A                     \   
                                /----^----\                \  
      вторая минута       C           \               B
                             /--^--\          \           /--^--\ 
      третья минута    D       \         E        F           \     
                         /--^-\       \     /--^--\   /--^--\     \
                     ...   ...    ... ...    ... ...    ...   ...

 6. AVL – деревья. Обозначим через f(n) число листьев в AVL – дереве высоты n. Тогда f(0) = 1, f(1) = 1, f(2) = 2.

medv_fib_12

   Если AVL – дерево имеет высоту n, то его левое поддерево (например, для определенности) имеет высоту n – 1, а правое n – 2. Количество листьев тогда равно

f(n) = f(n – 1) + f(n – 2),

   то есть числам Фибоначчи.

   7. Резисторы. Обозначим через f(n) сопротивление системы из n резисторов. Очевидно, что f(1) = 1, f(2) = 2. Докажем по индукции, что

medv_fib_13при четном n  и medv_fib_14 при нечетном n.

   Если система состоит из четного количества резисторов, то следующий резистор соединяется параллельно и результирующее сопротивление равно

medv_fib_15

   В случае нечетного количество резисторов соединение со следующим резистором происходит последовательно и результирующее сопротивление равно

medv_fib_16

   8. Замораживание Фибоначчи [Вальядолид, 495]. Поскольку n ≤ 5000, то для нахождения fn следует воспользоваться классом BigInteger. Найдем и запомним в массиве m все значения fn (0 ≤ n ≤ 5000) и для каждого входного n будем выводить m[n] = fn.

Реализация. Вычислим все значения fn (0 ≤ i ≤ 5000) и занесем их в массив m[5001]. Поскольку f5000 содержит не более 1100 десятичных знаков, то установим MAXLENGTH = 1100.

#include< stdio.h >

#include< memory.h >

#define MAXLENGTH 1100

class BigInteger{ . . .};

BigInteger m[5001];

void main(void)

{

  int i, n;

   Положим m[1] = 1 и воспользуемся рекуррентной формулой m[i] = m[i -1] + m[i - 2].

  m[1] = BigInteger(1);

  for (i = 2; i < 5001; i++) m[i] = m[i-1] + m[i-2];

Для каждого входного значения n выводим fn = m[n] в соответствии с требуемым форматом.

  while(scanf("%d",&n) == 1)

  printf("The Fibonacci number for %d is ",n),m[n].print();

}

   9. Луч сквозь стекло  [Вальядолид, 10334]. При наложении двух стеклянных пластин образуется одна внутренняя сторона и две внешние, относительно которых может отражаться луч света. Каждый проход луча с n отражениями будем кодировать последовательностью нулей и единиц длины n: если отражение осуществляется относительно внутренней стороны, то ставим 1, если относительно внешней – то 0. Например, показанному ниже движению луча с 4 отражениями соответствует последовательность 1, 0, 0, 0.

medv_fib_17

   Можно заметить, что две единицы в такой последовательности никогда не будут стоять вместе, потому что два последовательных отражения относительно внутренней стороны никогда не могут иметь место. Таким образом, количество возможных проходов луча с n отражениями равно количеству последовательностей из 0 и 1 длины n, в которых две единицы не стоят вместе. Количество таких последовательностей равно числам Фибоначчи (задача 10450). Числа Фибоначчи имеют вид: f0 = 0, f1 = 1, f2 = 1, fi = fi-1 + fi-2. Число способов an прохода луча света сквозь пластины равно fn+2.

   Поскольку n ≤ 1000, то следует воспользоваться классом BigInteger.

   Пример. Варианты прохождения луча сквозь пластины для n = 0, 1, 2 показаны выше на рисунке. При этом a0 = f2 = 1, a1 = f3 = 2, a2 = f4 = 3.

   Реализация. Вычислим все значения ai (0 £ i £ 1000), занесем их в массив m[1001]. Поскольку a1000 = f1002 содержит не более 210 десятичных знаков, то установим MAXLENGTH = 210.

#include< stdio.h >

#include< memory.h >

#define MAXLENGTH 210

class BigInteger{ . . .};

BigInteger m[1001];

void main(void)

{

  int i,n;

   Вычислим все значения m[i] = ai, 0 £ i £ 1000. Положим m[0] = 1, m[1] = 2, а далее воспользуемся рекуррентной формулой m[i] = m[i -1] + m[i - 2].

  m[0] = BigInteger(1); m[1] = BigInteger(2);

  for (i = 2; i < 1001; i++) m[i] = m[i-1] + m[i-2];

   Читаем входное значение n и выводим m[n].

  while (scanf("%d",&n) == 1) m[n].print();

}

   10. Шум мирового кубка  [Вальядолид, 10450]. Обозначим через f(n) количество искомых последовательностей из 0 и 1 длины n. Если на первом месте последовательности будет находиться 0, то начиная со второго места можно построить f(n – 1) последовательностей. Если на первом месте стоит 1, то на втором месте обязательно должен стоять 0, а на последующих n - 2 свободных местах можно построить f(n – 2) последовательностей.

medv_fib_18

   При этом f(1) = 2 (имеем две последовательности длины 2: 0 и 1), f(2) = 3 (последовательности 00, 01, 10). Значения f(n) образуют числа Фибоначчи . Известно, что f0 = 0, f1 = 1, f2 = 1, fi = fi-1 + fi-2. Учитывая начальные условия, получим: f(n) = fn+2.

   Пример. Рассмотрим второй тест. Всего существует 5 последовательностей из 0 и 1 длины 3, в которых две единицы не стоят рядом: 000, 001, 010, 100, 101.

   Реализация. В массиве fib вычислим значения f(n): f(n) = fib[n]. Для n > 44 значения f(n) будут выходить за границы типа int, поэтому воспользуемся 64 - битовым целочисленным типом long long (__int64).

#include< stdio.h >

int tests, i, n;

long long fib[51];

void main(void)

{

   Нахождение значений f(n) совершим в цикле:

  fib[1] = 2; fib[2] = 3;

  for(i = 3; i < 51; i++) fib[i] = fib[i-1] + fib[i-2];

Читаем количество тестов и для каждого входного n выводим значение fib[n].

  scanf("%d",&tests);

  for (i = 1; i <= tests; i++)

  {

    scanf("%d",&n);

    printf("Scenario #%d:\n",i);

    printf("%lld\n\n",fib[n]);

  }

}

   11. Числа Фибоначчи  [Вальядолид, 10579]. Воспользуемся классом BigInteger. Для каждого входного n вычислим значение f(n), используя приведенную в условии рекуррентную формулу.

Реализация. Воспользуемся классом BigInteger. Положим длину чисел MAXLENGTH равной 1001.

#include< cstdio >

#include< memory >

#include< string >

#define MAXLENGTH 1001

using namespace std;

class BigInteger{ . . .};

void main(void)

{

   Читаем входное значение n. Изначально положим a = f(0) = 0, b = f(1) = 1. Во вложенном цикле while после выполнения i - ой итерации имеют место соотношения: a = f(i), b = f(i + 1). Выполнив цикл n раз, выводим a = f(n).

  BigInteger a(0), b(1), temp(0);

  int n;

  while (scanf("%d",&n) == 1)

  {

    a = BigInteger(0); b = BigInteger(1);

    while (n--) temp = a, a = b, b = temp + a;

    a.print();

  }

}

   12. Пчела [Вальядолид, 11000]. Обозначим n - ое число Фибоначчи через f(n). Тогда через n лет число самцов в пчелином семействе будет равно f(n) – 1, а общее число пчел f(n + 1) – 1. Через n = 0 лет семейство состоит из единственной пчелы самки, то есть имеется 0 самцов и 1 пчела. Положим f(0) = 1, f(1) = 2. Далее по индукции докажем справедливость приведенного утверждения. После n + 1 года число самцов равно суммарному числу самок и самцов после n - го года, то есть f(n + 1) – 1. Число самок после n + 1 года равно числу самцов после n - го года плюс одна бессмертная самка, то есть f(n) – 1 + 1 = f(n). Таким образом общее число пчел после n + 1 года равно f(n + 1) – 1 + f(n) = f(n + 2) – 1.

   Реализация. Искомые числа Фибоначчи не превосходят 232. Вычислим их первые 50 значений и занесем в массив f типа long long.

#include< stdio.h >

long long f[50];

void main(void)

{

  int i, n;

   Заполним массив f числами Фибоначчи.

  f[0] = 1; f[1] = 2;

  for(i = 2; i < 50; i++) f[i] = f[i-1] + f[i-2];

Для каждого входного n выведем результат.

  while (scanf("%d",&n),n >= 0)

    printf("%lld %lld\n",f[n]-1,f[n+1]-1);

}

   13. Флаги [Тимус 1225]. Обозначим через fred(n) и fwhite(n) количество способов раскраски флага из n полос при условии, что первой полосой будет соответственно красная или белая. Тогда

fred(n) = fwhite(n – 1) + fwhite(n – 2), fred(1) = 1, fred(2) = 1;

fwhite(n) = fred(n – 1) + fred(n – 2), fwhite(1) = 1, fwhite(2) = 1.

Если f(n) – искомое общее количество способов раскраски, то

f(n) = fred(n) + fwhite(n)

Поскольку fred(1) = fwhite(1) = 1, fred(2) = fwhite(2) = 1, а fred(n) и fwhite(n) одинаковыми формулами выражаются друг через друга, то fred(n) = fwhite(n) = fn, где fnn-ое число Фибоначчи. Таким образом f(n) = 2 * fn.

   Реализация. В массиве fib вычислим значения fred(n): fred(n) = fib[n]. Для n > 44 значения fred(n) будут выходить за границы типа int, поэтому воспользуемся 64 - битовым целочисленным типом __int64.

__int64 fib[46];

Читаем входное значение n. Нахождение значения fib[n] совершим в цикле:

scanf("%d",&n);

fib[1] = 1; fib[2] = 1;

for (i = 3; i <= n; i++) fib[i] = fib[i-1] + fib[i-2];

   Выводим результат f(n) = 2* fred(n) = 2 * fib[n]:

printf("%I64d\n",2*fib[n]);

   14. Определитель. Обозначим через f(n) значение определителя. Тогда  f(1) = 1, f(2) = 2. Раскрывая определитель по первой строке, получим:

f(n) = f(n – 1) + f(n – 2)

   Откуда f(n) = Fn+1.

15. Бесконечная сумма. Положим x = 1/10 в производящей функции чисел Фибоначчи. Получим:

medv_fib_19

СПИСОК ИСПОЛЬЗОВАННЫХ ЗАДАЧ

[Вальядолид] acm.uva.es/problemset: 495 (Замораживание Фибоначчи), 10334 (Луч сквозь стекло), 10450 (Шум мирового кубка), 10579 (Числа Фибоначчи), 11000 (Пчела).

[Тимус] acm.timus.ru: 1225 (Флаги).