Zadanie 1. Liczby Fibonacciego

Liczby Fibonacciego są definiowane w następujący sposób:

FIndeks dolny 1 = 1, FIndeks dolny 2 = 1,

FIndeks dolny n = FIndeks dolny n - 1 Indeks dolny koniec + FIndeks dolny n - 2 Indeks dolny koniec dla = 3, 4, …

Rekurencyjny algorytm, który służy do obliczania wartości dla dowolnego n >= 1, można zapisać następująco:

Linia 1. funkcja F otwórz nawias okrągły n zamknij nawias okrągły. Linia 2. jeśli n znak równości 1 lub n znak równości 2 dwukropek. Linia 3. wynikiem jest 1. Linia 4. w przeciwnym razie dwukropek. Linia 5. wynikiem jest F otwórz nawias okrągły n minus 1 zamknij nawias okrągły plus F otwórz nawias okrągły n minus 2 zamknij nawias okrągły.

Zadanie zostało opracowane przez CKE i pojawiło się na I części egzaminu maturalnego z informatyki w czerwcu 2018 roku (poziom rozszerzony, egzamin w tzw. starej formule). Cały arkusz można znaleźć na stronie internetowej CKE.

Zadanie 1.1

Zapisz w wybranej przez siebie notacji (w języku programowania lub w pseudokodzie) algorytm iteracyjny, który służy do obliczania wartości liczby dla dowolnego  ≥ 1. Algorytm nie może używać tablic.

Rozwiązanie przedstawimy przy użyciu pseudokodu ze względu na fakt, że zadania maturalne dotyczące programowania można rozwiązać w wybranym języku programowania: C++,  Java lub Python.

Praca domowa

Zaimplementuj przedstawione rozwiązanie w wybranym języku programowania: C++, Java, Python.

Przykładowe rozwiązanie:

Mamy przedstawić algorytm, który będzie obliczać wartość elementu ciągu Fibonacciego o podanym indeksie. Posłużymy się techniką iteracyjną (czyli wykonamy określoną liczbę powtórzeń pewnych czynności).

  1. Definiujemy zmienną indeks, która będzie przechowywać indeks wyliczanego elementu ciągu:

Linia 1. indeks ← n.
  1. Piszemy instrukcję warunkową umożliwiającą obliczenie wartości pierwszego lub drugiego elementu ciągu Fibonacciego. W obu przypadkach podajemy wówczas wartość 1:

Linia 1. indeks ← n. Linia 3. jeżeli indeks znak równości 1 lub indeks znak równości 2 dwukropek. Linia 4. wypisz otwórz nawias okrągły 1 zamknij nawias okrągły. Linia 5. w przeciwnym razie dwukropek.
  1. Aby obliczyć wartość elementu o indeksie numer 3 lub wyższym, stosujemy iteracjęiteracjaiterację. Tworzymy najpierw trzy zmienne:

    • aktualna – przechowuje wartość wyliczoną dla obecnego indeksu,

    • poprzednia – przechowuje wartość elementu o indeksie niższym o 1,

    • bPoprzednia – przechowuje wartość elementu o indeksie niższym o 2.

Linia 1. indeks ← n. Linia 3. jeżeli indeks znak równości 1 lub indeks znak równości 2 dwukropek. Linia 4. wypisz otwórz nawias okrągły 1 zamknij nawias okrągły. Linia 5. w przeciwnym razie dwukropek. Linia 6. aktualna ← 0. Linia 7. poprzednia ← 1. Linia 8. bPoprzednia ← 1.
  1. Tworzymy pętlę dla, w której będą obliczane wartości kolejnych elementów ciągu Fibonacciego (licznik pętli inicjujemy wartością 3, ponieważ dwa pierwsze elementy ciągu już znamy):

Linia 1. indeks ← n. Linia 3. jeżeli indeks znak równości 1 LUB indeks znak równości 2 dwukropek. Linia 4. wypisz otwórz nawias okrągły 1 zamknij nawias okrągły. Linia 5. w przeciwnym razie dwukropek. Linia 6. aktualna ← 0. Linia 7. poprzednia ← 1. Linia 8. bPoprzednia ← 1. Linia 10. dla i znak równości 3 przecinek 4 przecinek kropka kropka kropka przecinek indeks wykonuj dwukropek.
  1. Wewnątrz pętli wykonane zostaną trzy działania:

    1. obliczenie wartości elementu ciągu o aktualnym indeksie (suma dwóch poprzednich elementów);

    2. wartość o indeksie niższym o 1 na potrzeby następnego cyklu pętli stanie się wartością o indeksie niższym o 2;

    3. wartość aktualna na potrzeby następnego cyklu pętli stanie się wartością o indeksie niższym o 1.

Linia 1. indeks ← n. Linia 3. jeżeli indeks znak równości 1 LUB indeks znak równości 2 dwukropek. Linia 4. wypisz otwórz nawias okrągły 1 zamknij nawias okrągły. Linia 5. w przeciwnym razie dwukropek. Linia 6. aktualna ← 0. Linia 7. poprzednia ← 1. Linia 8. bPoprzednia ← 1. Linia 10. dla i znak równości 3 przecinek 4 przecinek kropka kropka kropka przecinek indeks wykonuj dwukropek. Linia 11. aktualna ← poprzednia plus bPoprzednia. Linia 12. bPoprzednia ← poprzednia. Linia 13. poprzednia ← aktualna. Linia 15. wypisz otwórz nawias okrągły aktualna zamknij nawias okrągły.

Schemat oceniania:

  • 2 p. – za poprawny algorytm (w tym za prawidłowe zapisanie warunków początkowych i iteracji 1 p.).

  • 1 p. – za zapamiętanie tylko dwóch poprzednich wyrazów ciągu.

  • 0 p. – za podanie odpowiedzi błędnej albo brak odpowiedzi.

Za przedstawione rozwiązanie zadania otrzymalibyśmy 2 punkty, ponieważ prawidłowo zapisane zostały warunki początkowe (dla indeksów 1 i 2) oraz pętla iteracyjna.

Zadanie 1.2

Aby obliczyć , wywołano najpierw funkcję iteracyjną, a potem – rekurencyjną. Okazało się, że czas trwania obliczeń realizowanych przez funkcję rekurencyjną był długi, podczas gdy funkcja iteracyjna prawie natychmiast podała wynik. Uzasadnij długi czas działania funkcji rekurencyjnej.

Przykładowe rozwiązanie:

Jedną z lepszych wizualizacji rekurencji jest zapisanie jej w postaci drzewa, w którym poszczególne wywołania funkcji uruchamiają kolejne jej wywołania (aż do napotkania przypadku podstawowego). Wielokrotne wywoływanie powoduje wielokrotne obliczanie tych samych wartości. Poszczególne elementy ciągu Fibonacciego wyliczane są zatem bez brania pod uwagę wyrazów już znanych. Za każdym razem funkcja rekurencyjna dochodzi do przypadku podstawowego. Ponadto im dalszy wyraz ciągu Fibonacciego ma zostać obliczony, tym więcej powtórzeń jest wykonywanych. Z tego powodu taka technika okazuje się wolniejsza od metody iteracyjnej i daje złożoność wykładniczą od n.

Schemat oceniania:

  • 1 p. – za poprawną odpowiedź.

  • 0 p. – za podanie odpowiedzi błędnej albo brak odpowiedzi.

Nasza odpowiedź jest trochę obszerniejsza niż ta przedstawiona w arkuszu sporządzonym przez CKE, ale wyjaśnia powód wolniejszego działania algorytmu rekurencyjnego. W rezultacie na egzaminie otrzymalibyśmy 1 punkt.

Słownik

iteracja
iteracja

technika programowania polegająca na wielokrotnym powtarzaniu zapisanego ciągu instrukcji aż do spełnienia określonego warunku

rekurencja
rekurencja

technika programowania, w której funkcja wywołuje samą siebie aż do napotkania przypadku podstawowego, czyli takiego, którego nie da się rozłożyć na mniejsze problemy; przykład przypadku podstawowego dla obliczania piątego wyrazu ciągu Fibonacciego: fib(4) = fib(3) + fib(2) = (fib(2) + fib(1)) + (fib(1) + fib(0)) = 

= ((fib(1) + fib(0)) + fib(1)) + fib(1)) + (fib(1) + fib(0)) =

= ((1 + 0) + 1) + (1 + 0) = 3

przypadek podstawowy
przypadek podstawowy

wartość, dla której funkcja rekurencyjna zwraca określony wynik