Cześć, matura rozszerzona z informatyki to temat kolejnego wpisu. Na prośbę kilku osób postanowiłem się rozprawić z tym tematem. Na wstępie zaznaczam od razu, że rozwiązuję tu problemy tylko natury programistycznej. Są one jednak poruszane w ponad 90% zadań z zeszłorocznej majowej matury. 

W ramach rozwiązywania zadań przeanalizuję następujące problemy i zagadnienia:

  • Zadanie 1. Złożoność czasowa liniowa i logarytmiczna
  • Zadanie 2. Struktury drzewiaste i analiza algorytmu rekurencyjnego
  • Zadanie 3. Systemy liczbowe inne niż dwójkowy i dziesiętny
  • Zadanie 4. Plik tekstowym, wyznaczanie liczb będących potęgą innej liczby oraz silnia
  • Zadanie 5. Praca z arkuszem kalkulacyjnym
  • Zadanie 6. Praca z zapytaniami SQL

Spore spektrum zagadnień, więc nie traćmy czasu i zacznijmy!

Matura rozszerzona z informatyki — Wprowadzenie

Temat wpadł do mnie totalnie z zaskoczenia. Ukazał mi jednak ogrom możliwości, co do ciekawych przypadków zadań i pomocy młodym adeptom sztuki programowania!

Planuję, by materiały te stały się kompleksowym poradnikiem w kwestii matur z lat poprzednich. Cyklicznie dodam tu pełne spektrum materiałów — od najwcześniejszych lat po najnowsze matury, od próbnych po „majowe”.

Na początku arkusza musimy wpisać informacje na temat języka. W moim przypadku będzie to język Python, jednak tak naprawdę to znajomość sposobu rozwiązania będzie tu kluczowa, a nie sam język. Postaram się też nawiązać do ciekawych rzeczy, które są tak jakby drugim dnem zadania.

Matura rozszerzona z informatyki — Zadanie 1

ezpośrednio nie są związane z programowaniem.  Matura rozszerzona z informatyki - maj 2019 - Zadanie 1

Pierwsze zadanie dzieli się na dwa podzadania, za które można łącznie zgarnąć 6 punktów. Na pierwszy rzut oka wydaje się bardzo skomplikowane. Jednak gdy czytamy jego treść, to od razu rzuca się kilka wskazówek.

Po pierwsze Małgosia wypisuje swoje liczby jako pierwsza i są one tylko nieparzyste, następnie Jaś wypisuje parzyste. Liczby mogą być dowolnie duże, nie mamy też informacji na temat ich sortowania. Wiemy tylko, że od lewej w tablicy będą te od Małgosi. To wbrew pozorom bardzo ważne wskazówki. 

Kolejne aspekty, które musimy wydedukować to takie, że Małgosia i Jaś nie muszą podać dokładnie takiej samej ilości liczb. Jednak podadzą co najmniej jedną liczbę, więc tu mamy pewność co do ilości początkowej. Mamy więc trzy możliwości.

Ilość liczb Małgosi = Ilość liczb Jasia 

11, 5, 3, 6, 2, 88

Ilość liczb Małgosi > Ilość liczb Jasia 

11, 5, 3, 53, 101, 6, 2, 88

Ilość liczb Małgosi < Ilość liczb Jasia 

11, 5, 3, 6, 2, 88, 42, 12

Jeszcze wskazówki ogólne. Musimy zwrócić uwagę na złożoność obliczeniową algorytmu, która musi być różna od liniowej. To informacja, że nie możemy po prostu użyć pętli i sprawdzić, iteracja po iteracji, czy kolejna sprawdzana liczba jest parzysta. To znaczące utrudnienie, ale damy radę!

Dodatkowo nie można stosować nic więcej, niż standardowe konstrukcje programistyczne. Na koniec dostaliśmy mały przykład tego, jak mają nazywać się nasze zmienne. Tablica ma być zapisywana jako A, ilość łączna liczb jako n oraz wynik jako mała litera w. Warto się tego trzymać, by w prosty sposób nie stracić punków za zadanie.

Analiza

Czas przejść do rozwiązania. Algorytm zamknę w funkcji o nazwie pierwszaLiczbaJasia, która na wejście przyjmie tablicę liczb o nazwie A. Następnie zadeklaruję zmienną n, o której wspomniałem wyżej oraz dwie zmienne pomocnicze — i oraz j.

Warto w tym miejscu napomnieć, że zmienne te są zapisane pojedynczymi literami głównie dla zaoszczędzenia miejsca na papierze, którego mamy mało na egzaminie maturalnym. W normalnej pracy nie będzie miejsca na tego typu nazwy zmiennych. 

W zmiennej i będziemy trzymać indeks startowy (warto zauważyć, że startujemy od 1, a nie od 0, ponieważ mamy pewność, że pierwszy element w tablicy będzie zawsze nieparzysty, Małgosia musi dodać chociaż jedną liczbę), w zmiennej j natomiast przechowamy ilość liczb w tabeli. Te zmienne będą miały zmieniane wartości, dlatego nie możemy na przykład skorzystać ze zmiennej n bezpośrednio. Dodatkowo zadeklaruję jeszcze dwie zmienne — zmienną k oraz w. K to zmienna, która będzie przetrzymywać aktualny krok iteracji. Zmienną w omawiałem wyżej.

Przejdźmy dalej.

Główny fragment

Głowna część algorytmu będzie znajdować się w pętli while, która będzie się kręcić do momentu, aż zmienna j zrówna się albo będzie większa od zmiennej i. O aktualizacji tych zmiennych za chwilę. Kolejnym krokiem będzie wyznaczenie zmiennej k, która będzie wskazywać aktualnie sprawdzany indeks. Ważne jest, by zmienna k trafiała w środek z przedziału od i do j.

Dla przykładu, w pierwszej iteracji po zbiorze 1,3, 5, 7, 8, 2 zmienna k przechowa wartość 3, czyli będzie wskazywać na cyfrę 7. Warto tu zobaczyć, że użyty jest operator arytmetyczny //. Jest to dzielenie w dół. W naszym przypadku i + j daje 7 i podzielone na 2 da 3.5. Dzielenie w dół zaokrągla do pełnych wartości, czyli tu będzie to 3.

Przechodząc dalej, sprawdzamy, czy jesteśmy na kroku parzystym, czy nieparzystym. Gdy liczba jest nieparzysta, zmieniamy zmienną i zwiększając ją o 1. Gdy mamy liczbę parzystą, to jesteśmy w dobrej części zbioru i musimy zmienną j zmniejszyć o jeden, by iść w lewą stronę. Dzięki temu przy następnym kroku pętli znów celować zmienną k w środek przedziału od i do j.

Na końcu każdej iteracji sprawdzamy warunek końcowy. Jeżeli ostatnim przeglądanym przez nas elementem jest liczba nieparzysta, a następnym w kolejności liczba parzysta, to właśnie ta liczba o indeksie i+1 jest naszą odpowiedzią!

Zobacz przykład

Wyliczamy zmienną k — trafia ona na element numer 12. Jest to liczba 777. Liczba jest nieparzysta, więc przesuwamy zmienną i z 1 na 12, ponieważ do tego momentu będą tylko liczby nieparzyste. Sprawdzamy warunkiem końcowym, czy 777 jest nieparzysta, a 901 parzysta. Nie jest to prawdą, więc przechodzimy dalej.

Pierwsza iteracja

A = 1, 65, 77, 109, 111, 97, 43, 41, 11, 13, 411, 777, 901, 92, 90, 2, 4, 8, 6, 44, 96, 100

Druga iteracja to kolejne wyliczenie zmiennej k. 12 + 22 daje 34. Dzielimy na pół i otrzymujemy 17. Patrzymy, co pod tym indeksem znajduje się w tabeli. Jest to wartość 8. Tym razem nie zmieniamy zmiennej i lecz j obniżając zmienną k o 1. Warunek końcowy mówi nam, że jesteśmy na liczbie parzystej, więc z automatu go odrzucamy i robimy kolejną iterację. 

Druga iteracja

A =1, 65, 77, 109, 111, 97, 43, 41, 11, 13, 411, 777, 901, 92, 90, 2, 4, 8, 6, 44, 96, 100

Trzecia iteracja to kolejne wyliczenie zmiennej k. 12 + 16 daje 28. Dzielimy na pół i otrzymujemy 14. Patrzymy, co pod tym indeksem znajduje się w tabeli. Jest to wartość 92. Tym razem również nie zmieniamy zmiennej i lecz j obniżając k o 1. Warunek końcowy mówi nam, że jesteśmy na liczbie parzystej, więc z automatu go odrzucamy i robimy kolejną iterację. 

Trzecia iteracja

A =1, 65, 77, 109, 111, 97, 43, 41, 11, 13, 411, 777, 901, 92, 90, 2, 4, 8, 6, 44, 96, 100

Czwarta iteracja to kolejne wyliczenie zmiennej k. 12 + 14 daje 26. Dzielimy na pół i otrzymujemy 13. Patrzymy, co pod tym indeksem znajduje się w tabeli. Jest to wartość 901. Tym razem zmieniamy zmienną i, która będzie wynosić 15. Warunek końcowy mówi nam, że jesteśmy na liczbie nieparzystej, więc sprawdzamy, czy liczba na prawo od 901 jest parzysta. Oczywiście jest! To wypisuje na ekran rozwiązanie i kończy działanie pętli

Czwarta iteracja

A =1, 65, 77, 109, 111, 97, 43, 41, 11, 13, 411, 777, 901, 92, 90, 2, 4, 8, 6, 44, 96, 100

Jak widać, można zoptymalizować rozwiązanie dla tego przykładu, bo już na 3 iteracji byliśmy we właściwym miejscu. Oczywiście pozostawiam to Tobie. 

Złożoność czasowa

Teraz też możemy odpowiedzieć sobie na drugie pytanie, czyli jaka jest złożoność czasowa danego algorytmu. Oczywiście widzimy tu pewną analogię do algorytmu nazywanego „dziel i zwyciężaj”. Dzielimy nasz problem na mniejsze podproblemy, te mniejsze na jeszcze mniejsze aż do momentu, gdy dochodzimy do prawidłowego rozwiązania. Jest to więc złożoność logarytmiczna. Na temat złożoności pisałem więcej tutaj.

Implementacja
# Matura rozszerzona z informatyki - maj 2019
def pierwszaLiczbaJasia(A):
    n = len(A)
    i = 1
    j = n

    k = 0
    w = 0

    while i <= j:
        k = (i + j) // 2

        if int(A[k]) % 2 == 1:
            i = k + 1
        else:
            j = k - 1

        if int(A[k]) % 2 == 1 and int(A[k+1]) % 2 == 0:
            w = A[k+1]
            print("Pierwsza parzysta liczba od lewej to: " + str(w))
            break

A = [5,99,3,7,111,13,4,24,4,8]
pierwszaLiczbaJasia(A)


Matura rozszerzona z informatyki — Zadanie 2

ezpośrednio nie są związane z programowaniem.  Matura rozszerzona z informatyki - maj 2019 - Zadanie 2

Zadanie drugie to bardzo ciekawy przykład analitycznego myślenia i analizy kodu w pracy zawodowej. Najpierw uważnie wczytajmy się w pseudokod. Mamy do zbadania małą funkcję, która działa rekurencyjnie. Rekurencja osiągnie koniec, gdy spełniony zostanie warunek, mówiący o tym, że długość pierwszego parametru będzie równa wartości drugiego.

Funkcja wywoła samą siebie w pętli tyle razy ile ostatni parametr. W uwagach jeszcze dostajemy trzy informacje. Jak wyliczana jest długość napisu, potwierdzenie konkatenacji stringów oraz czym zajmuje się funkcja napis. 

Zadanie 2.1

Naszym pierwszym zadaniem jest wydedukowanie, jakie będą kolejne dwa wywołania oraz kolejność wywołań samej funkcji zaczynając od korzenia drzewa. Patrząc na dwa napisy po lewej, które zostały przekazane do funkcji Pisz() jako parametr, czyli „00” oraz „01” buduje się już w głowach pewna analogia. 

Ale od początku. Funkcja Pisz jako ostatni parametr przyjmuje wartość 2, czyli każde wywołanie funkcji wywołuje dwie kolejne. W pierwszym parametrze wejściowym, po prawej stronie drzewa posiadamy wartość „1”. Mamy więc już informację, że kolejne dwa wywołania funkcji będą wyglądać następująco:

pisz(„1x”, 2, 2) oraz pisz(„1x”, 2, 2) 

Już niemal wszystko jest jasne. Wywołania funkcji będą różnić się elementem pierwszej wartości, który to element zaprezentowałem jako x. Rzućmy raz jeszcze okiem na pętle, w której funkcja wywołuje samą siebie. Widzimy, że jedynka w pierwszym parametrze to niejako spadek z poprzedniego wywołania, x natomiast to wartość aktualnego iteratora pętli. Pętla iteruje od 0 do 1, ponieważ jako trzeci parametr przekazujemy 2. Wszystko stało się jasne. Najpierw x równa się 0, w drugiej iteracji 1. W wykropkowane miejsca wstawmy więc następujące wywołania funkcji:

pisz(„10”, 2, 2) oraz pisz(„11”, 2, 2) 

Mając przeanalizowany sposób działania algorytmu, punkt b wydaje się już tylko formalnością. Pętla działa od 0 do 1, więc każdy poziom zagłębiamy się najpierw z zerami po lewej stronie drzewa, później przechodzimy do jedynek od dołu drzewa i wracamy do samej góry. Następnie zagłębiamy się w prawą stronę drzewa, patrząc znów najpierw na 0, w przypadku rozgałęzień.

Jest to dość ciekawy przykład grafów i przechodzenia grafu w głąb, o którym miałem przyjemność napisać tutaj.

Odpowiedź wygląda następująco. 

 Matura rozszerzona z informatyki – maj 2019 rozwiązanie zadania 2.1

Zadanie 2.2

Gdy mamy już przeanalizowany algorytm i wiemy, że musimy zawsze patrzeć na lewą stronę danego rozgałęzienia w pierwszej kolejności, to uzupełnienie tabeli z zadania 2.2 będzie proste. Musimy uzupełnić dwie informacje, jakie napisy będziemy otrzymywać kolejno oraz to, jaka będzie łączna ilość wywołań. Ściągę mamy wyżej w postaci poprawnie uzupełnionego drzewa. 

Funcja pisz(„”, 3, 2)

Na pierwszy ogień idzie wywołanie pisz(„”, 3, 2), gdzie drugi parametr steruje naszym poziomem zagłębienia. Początek drzewa będzie analogiczny, jak wyżej, lecz musimy zejść jeszcze niżej o jeden poziom i zebrać napisy końcowe. Rysunek poglądowy, który można zrobić sobie w brudnopisie wygląda mniej więcej tak:

Matura rozszerzona z informatyki – maj 2019 zadanie 2.2

Rysunek wyżej jest poglądowy i interesują nas tylko elementy zaznaczone zieloną ramką. Wypisujemy od lewej strony:

  1. „000”
  2. „001”
  3. „010”
  4. „011”
  5. „100”
  6. „101”
  7. „110”
  8. „111”

Uwaga na koniec, widzimy, że są pięknie przedstawione liczby od 0 do 7 zapisane binarnie na trzech bitach! Możemy wywnioskować, że parametr numer dwa określa liczbę bitów na wyjściu a końcowy napis w tym przypadku to zwykła binarka.

Dzięki rozrysowanemu drzewu powyżej widzimy też, że funkcja została wywołana 15 razy łącznie z wywołaniem zerowym.

Funkcja pisz(„”, 2, 3)

Teraz czas na sytuację odwrotną. Wywołanie funkcji pisz(„”, 2, 3). Tu środkowy parametr ustawiony mamy na 2, czyli poziom zagłębienia będzie identyczny jak w drzewie z zadania 2.1. Drzewo jednak będzie bardziej rozgałęzione wszerz. Na rysunku poglądowym ograniczę się tylko do nawiasów, bez nazwy funkcji, tak by rysunek był w miarę czytelny. Będzie on wyglądał następująco:

Matura rozszerzona z informatyki – maj 2019 zadanie 2.2.2

Tu również interesuje nas tylko pierwszy parametr funkcji z zielonej ramki. Będą to odpowiednio:

  1. „00”
  2. „01”
  3. „02”
  4. „10”
  5. „11”
  6. „12”
  7. „20”
  8. „21”
  9. „22”

Po przeliczeniu wszystkich wywołań wyszło nam, że ilość ta będzie równa 13 łącznie z wywołaniem zerowym.

Zadanie 2.3

Trzecia część zadania drugiego wydaje się najbardziej skomplikowana i zarowno w drugim zadaniu jak i w całym arkuszu „matura rozszerzona z informatyki”. Za nami jednak stoi doświadczenie zdobyte analizą funkcji i rozpisywaniem jej zachowań w przypadku różnych parametrów wejściowych. Widzimy sytuację, gdzie drzewo rośnie albo wszerz, albo w głąb. Jest to idealne zadanie pokazujące struktury drzewiaste (inaczej drzewa binarne, tu przykład regularnego drzewa binarnego). 

Aby wywnioskować, jakim wzorem możemy określić liczbę wywołań, musimy zastanowić się kolejny raz nad tym, jakie parametry przyjmuje funkcja i co od nich zależy. Pierwszy parametr niejako steruje zakończeniem funkcji i jest zależne od dwóch kolejnych parametrów. To, co określa nam, czy drzewo rysujemy pionowo, czy poziomo to parametr odpowiednio k i n. Jeżeli liczba k będzie większa od n, to wtedy będziemy rozciągać drzewo na boki. Gdy jednak n będzie większa, wtedy rozciągamy rysunek drzewa w dół. Jak już zauważyliśmy, im głębiej sięgamy, tym więcej robimy kroków, więc to ważna wskazówka.

Wstępna analiza

Spójrzmy teraz na nasz pierwszy poglądowy rysunek i zastanówmy się, jak utworzyć z tego jakiś wzór?

Na początku podzielę liniami rysunek, oddzielając każde z zagłębień.

Matura rozszerzona z informatyki – maj 2019 zadanie 2.3

Gdy zrobimy sumę każdego wywołań, z każdej linii dostaniemy coś takiego 1 + 2 + 4 + 8.

W pierwszej linii 1 wywołanie, w drugiej 2, w trzeciej 4 i w ostatniej 8. Mamy więc pierwszy punkt zaczepienia, a pisałem wyżej, że głębokość grafu wyznacza parametr n, więc to on determinuje, ile liczb (poziomów) będziemy sumować. 

Sumowanie więc możemy zapisać jako suma od 0 do n. Wartość k natomiast mówi nam, ile mamy wywołań funkcji na danym poziomie zagłębienia. Można z tego już stworzyć prosty wzorek, który mówi nam, że na poziomie 0, mamy 1 wywołanie, na drugim 2 i tak dalej jak w sumowaniu wyżej. 

Ostateczny wzór

Teraz tworzymy wzór, gdzie k damy jako podstawę, a liczba zagłębień jako wykładnik.

Powstanie następujący wzór:

Wykładnikiem więc jest nasze n i wzór będzie wyglądał tak jak poniżej!

Ogólnie ten punkt to w mojej opinii jedno z najcięższych zadań w tej maturze — trzeba albo bardzo mocno analitycznie myśleć, albo mieć dużą wiedzę na temat drzew binarnych.

Matura rozszerzona z informatyki — Zadanie 3

Matura rozszerzona z informatyki - maj 2019 zadanie 3

Uff po dwóch ciężkich zadaniach czas trochę się odmóżdżyć. Zadanie numer trzy jest dość przyjemne. Ja jednak od razu zaznaczam, że nie podejmę się wyjaśnienia zadania 3.3, ponieważ moje kompetencje w temacie sieci komputerowych nie są wystarczająco duże. Ten typ zadania jest mniej programistyczny, a bardziej bazuje na wiedzy ogólnej i tego jak działają bazy danych.

Dla mnie bazy danych są szczególne, ponieważ to od nich rozpocząłem swoją przygodę z komercyjnym programowaniem. Ale przejdę już do zadań.

Zadanie 3.1

Zadaniem naszym jest odpowiedzenie sobie na szereg pytań. Na początku jednak zapoznajmy się z tabelą Pracownicy. Mamy tam Numer porządkowy (najprawdopodobniej unikalny identyfikator), imię, nazwisko, stanowisko i numer działu. Moje uwagi co do samej tabeli to to, że numer działu i stanowisko kwalifikują się na klucze obce i osobne tabele słownikowe. Jest to jednak matura i zbyt wyniosły schemat bazy danych zajmowałby za dużo miejsca, więc zapewne dlatego takie uproszczenie. 

Pierwsze pytanie dotyczy prostego zapytania o ilość stanowisk. Odpowiedź sugerowana to wynik 5. Nie jest to jednak prawdą, ponieważ jest to suma wszystkich rekordów. Co innego, gdyby pobawić się z grupowaniem, wtedy faktycznie wartość wyniosłaby 5.

Pytanie numer dwa jest poprawne, wykluczamy z 9 rekordów trzech kierowników. Pytanie numer trzy również jest prawdziwe i to jest sytuacja, o której wspomniałem wyżej. Gdyby pogrupowane elementy policzyć, wtedy dostalibyśmy wartość 5. Ostatnie pytanie jest fałszywe. Klauzulę like używamy z napisami, a znaki, które chcemy pominąć, nie są sugerowane znakiem * lecz znakiem %. 

Odpowiedzi więc są następujące:

  1. F
  2. P
  3. P
  4. F

Zadanie 3.2

Mnożenie liczb binarnych jest prostą operacją. Binarne 1111110 oraz 101 to odpowiednio 126 i 5. Po pomnożeniu dziesiętnych wartości otrzymujemy liczbę 630.

Przejdźmy teraz po kolei. Mamy do sprawdzenia cztery liczby w czterech różnych systemach. Systemie czwórkowym, dwójkowym, ósemkowym i szesnastkowym. Ogólnie systemów może być tyle ile mamy cyfr, ale każdy z nich bazuje na tej samej zasadzie. Zaczynamy od prawej strony i podnosimy liczbę określającą system odpowiedniej potęgi i mnożymy ją razy tą cyfrę, która znajduje się w danym miejscu. Nic tak tego nie opisze jak przykład.

System czwórkowy

Na pierwszy ogień idzie liczba 21312 w systemie czwórkowym. Lecimy więc od prawej strony.

(4 do potęgi 0 razy 2) + (4 do potęgi 1 razy 1) + (4 do potęgi 2 razy 3) + (4 do potęgi 3 razy 1) + (4 do potęgi 4 razy 2) = 2 + 4 + 48 + 64 + 512 = 630. Jak widać, daje to prawdę. 

System binarny

Kolejno sprawdzamy, co kryje się pod binarną liczbą 1001010110.

(2 do potęgi 0 razy 0) + (2 do potęgi 1 razy 1) + (2 do potęgi 2 razy 1) + (2 do potęgi 3 razy 0) + (2 do potęgi 4 razy 1) + (2 do potęgi 5 razy 0) + (2 do potęgi 6 razy 1) + (2 do potęgi 7 razy 0) + (2 do potęgi 8 razy 0) + (2 do potęgi 9 razy 1) = 0 + 2 + 4 + 0 + 16 + 0 + 64 + 0 + 0 + 512 = 598. Jak widać, daje to fałsz.

System ósemkowy

Dalej mamy system ósemkowy i liczbę 1166.

(8 do potęgi 0 razy 6) + (8 do potęgi 1 razy 6) + (8 do potęgi 2 razy 1) + (8 do potęgi 3 razy 1) = 6 + 48 + 64 + 512 = 630. Jak widać, daje to prawdę.

System szesnastkowy

Ostatni został nam system szesnastkowy i liczba 276.

(16 do potęgi 0 razy 6) + (16 do potęgi 1 razy 7)  + (16 do potęgi 2 razy 2)  = 6 + 112 + 512 = 630. Jak widać jest to prawda.

Ostatecznie odpowiedzi wyglądają tak.

  1. P
  2. F
  3. P
  4. P

Matura rozszerzona z informatyki — Zadanie 4

Matura rozszerzona z informatyki – maj 2019 zadanie 4

Czas na część bardziej praktyczną. Mamy fajne zadanie do rozpracowania, które bazuje na pliku tekstowym. Podstawą każdego z zadań będzie wczytanie go do pewnej tablicy, na której w następnej kolejności wykonamy szereg działań.

Dodatkowo w zadaniu czwartym musimy operować na pliku przyklad.txt, który jest dostępny do pobrany na stronie CKE. Chodzi o plik Dane_PR2.ZIP. Z informacji wynika, że w pliku mamy 500 liczb z zakresu od 1 do 100 000. Skrypty mamy zapisać do pliku wyniki4.txt. Ważne by przestrzegać tych poleceń, bo możemy stracić punkty.

Jeszcze jedna uwaga. Warto przy testowaniu naszych algorytmów posługiwać się plikiem przyklad.txt. Jest on również dostępny w paczce, którą wskazałem wyżej. Czas przejść do pierwszego zadania.

Zadanie 4.1

Jest to jeden z moich faworytów w tym artkuszu. Zadanie bardzo podchwytliwe i bardzo mocno można się zdziwić. W pierwszej kolejności można sobie pomyśleć, że zadanie będzie polegało na wczytaniu z pliku rekordów, a następnie sprawdzenie za pomocą modulo, czy liczba podzielna jest przez trzy. Wynik takiego działania stwierdziłby, że mamy 179 liczb w pliku, które zgadzają się.

Nic bardziej mylnego, jest to błąd. Nie chodzi o modulo z trzech tylko o to, która liczba jest potęgą liczby 3. Można to sprawdzić za pomocą instrukcji warunkowej i sprawdzać, czy liczba z wczytanej linii jest podzielna bez reszty przez kolejno 3, 9, 27, 81, 243, 729, 2187, 6561, 19683 lub 59049. Następną z kolei potęgą jest 177147, ale w treści zadania mamy informacje, że liczbą największą w pliku może być 100000.

Takie instrukcje warunkowe jedno pod drugim to jest to jakieś rozwiązanie, ale niezbyt eleganckie prawda?

Wpadłem na inny pomysł. Skoro mamy liczbę, która jest wartością 3 podniesioną do 11 potęgi i nie mieści się ona w zbiorze to może wykorzystajmy ją do obliczeń. 

Implementacja

Ale od początku. Wczytajmy najpierw z pliku liczby.txt wartości linia po linii i zapiszmy ją w tablicy lines. Każda linia w tablicy to osobna wartość. Dalej zadeklaruję zmienną allCount, która to zmienna pozwoli na przechowanie końcowego wyniku.

Czas na najważniejszą część, stworzę funkcję isPower, która przyjmie sprawdzaną liczbę. I teraz dość sprytne zagranie, skoro liczba 177147 nie mieści się w zakresie, to pomoże nam. Wystarczy, że sprawdzimy modulo tej liczby ze sprawdzanej liczby. Jeżeli 3 do 11 dzieli się przez sprawdzaną liczbę bez reszty to jest ona potęgą liczby 3! Sprytne prawda? 

Teraz pozostaje tylko sprawdzić w pętli linia po linii każdą liczbę i posumować jedynki. Poprawny wynik to 18 liczb, które są potęgami 3.

with open('liczby.txt') as f:
    lines = f.readlines()

allCount = 0


def isPower(y):
    if 177147 % y == 0:
        return 1
    else:
        return 0

for line in lines:
    allCount += isPower(int(line))


print(allCount)

Zadanie 4.2

Czas wskoczyć na poziom wyżej. Zadanie numer dwa z zadania czwartego będzie opierało się na silni. Jest to jeden z moich ulubionych matematycznych tematów i bardzo fajnie implementuje się go w kodzie. Ale zacznijmy od początku. Musimy stworzyć taki algorytm, który oczywiście jak w poprzedniej części wrzuci liczby z pliku liczby.txt do tabeli. Kolejnym krokiem jest zadeklarowanie tablicy allNumbers, gdzie przechowamy wszystkie znalezione liczby.

Głównym zadaniem algorytmu będzie znalezienie takich liczb, których suma silni poszczególnych cyfr da wynik identyczny, jak sprawdzana liczba z pliku. Za to będzie odpowiadać funkcja factorial, która na wejście przyjmie analizowaną liczbę.

Następnie deklaracja zmiennej allSum, która przechowa posumowane wartości silni każdej z cyfr. Dalej uruchamiamy pierwszą pętlę. Będzie ona wykonywać się tyle razy, ile wynosi długość analizowanej liczby. Później deklaracja zmiennej k, która przechowa wartość silni każdej z cyfr. Obliczenie silni będzie odbywać się w zagnieżdżonej pętli, która będzie domnażać kolejne wartości iteratora. Warto zauważyć, że ptle iterują od zera, dlatego w zagnieżdzonej pętli iterator j podnoszę o 1.

Po tej całej operacji sumujemy poszczególne wyniki silni do zmiennej allSum i sprawdzamy, czy ta zmienna jest równa zmiennej wejściowej. Jeżeli tak, to dodajemy ją do listy. Na koniec pozostaje uruchomić w pętli stworzoną metodę. Uzupełni ona tablicę allNumbers, którą w kolejnej pętli przeczytamy i wypiszemy każdy ze znalezionych numerów.

Ten algorytm jest dość mocno zawiły, dlatego polecam każdemu poeksperymentowanie z nim. Dobrym sposobem analizy poza debugerem jest używanie w wielu miejscach funkcji print i analizowanie, co w danym miejscu się znajduje.

Implementacja
with open('liczby.txt') as f:
    lines = f.readlines()

allNumbers = []

def factorial(y):
    allSum = 0
    for i in range(len(y)):
        k = 1

        for j in range(int(y[i])):
            k *= (j + 1)

        allSum += k

    if str(allSum) == y:
        allNumbers.append(y)

for line in lines:
    factorial(line.strip())

for num in allNumbers:
    print(num)

Zadanie 4.3

Czas na trzecie i najbardziej skomplikowane podzadanie z czwartego zadania i w moim mniemaniu najtrudniejszym zadaniu w arkuszu „matura rozszerzona z informatyki”. Kluczem jest tu bardzo dokładne przeanalizowanie jego treści. 

Chodzi o znalezienie podciągu w ciągu wszystkich liczb, który będzie zawierał liczby, posiadające wspólny dzielnik większy od jedynki. Dla przykładu fragment ciągu:

2 5 9 6 9 3 2 ….

Sprawdzamy od lewej strony dwie pierwsze wartości, ich NWD jest 1, przechodzimy dalej. Pięć oraz dziewięć też nie mają NWD, więc idziemy dalej, 9 i 6 już posiadają i jest to 3, dalej przechodzimy i znów mamy dzielnik większy od 1, bo znów jest to 3. Przechodzimy o kolejny krok i mamy cyfry 9 oraz 3. One również posiadają wspólny dzielnik o wartości trzy. Dopiero ostatnia para cyfr zwraca NWD jako 1, dlatego przerywamy liczenie i zaczynamy od początku, szukając kolejnego ciągu, dłuższego od znalezionego. Znalezionym ciągiem jest 9 6 9 3.

Parametry, które musimy podać, to pierwszy element ciągu, jego długość oraz jego NWD. Dla naszego przykładu będzie to 9, 4, 3. Kryterium, po którym sprawdzamy dalej, jest długość podciągu. Jeżeli w ciągu znajdziemy dłuższy podciąg niż 4 elementy, który ma NWD kolejnych liczb różne od 1 to jego bierzemy pod analizę i końcowy wynik.

Zadanie trudne, ale przejdziemy do kodu. Na początku standardowo pobieramy wszystkie linie z pliku, dalej deklarujemy funkcję NWD. Otrzymuje ona na wejście dwie liczby i ona rekurencyjnie przechodzi w dół element po elemencie. Algorytm ten opisywałem w moim PDF bardziej szczegółowo. Wystarczy zapisać się na Newsletter.

Analiza

Główna funkcja to searchMaxLen, która będzie na wejściu miała kilka zadeklarowanych zmiennych, pierwsze trzy to nasze zmienne, gdzie przechowamy ostateczną odpowiedź, w kolejności, która wynika z treści zadania. Dodatkowo pobierzemy sobie długość tablicy, w której mamy pobrane liczby.

W pierwszej pętli zaczynamy od początku. Deklarujemy zmienną minNWD, która przechowa aktualnie najniższy wspólny dzielnik dla analizowanego podciągu i tak samo zmienna first, która przechowa pierwszy element analizowanego podciągu. Ostatnia zmienna k, to licznik, który przechowa informacje o długości podciągu. Mając te dane, możemy przejść do badania podciągu w drugiej pętli. Sprawdzamy element kolejny i ewentualnie aż do końca ciągu głównego.

Na początku wyliczamy NWD w sposób, jaki sugeruje treść zadania, czyli NWD( NWD(a, b), c), gdzie zapis NWD(a, b) to tak naprawdę nasza minNWD, której zmieniamy wartość pod koniec drugiej pętli. Ale wróćmy w górę. Skoro wyliczyliśmy wartość n, która przechowa NWD danej pary, sprawdzamy, czy jest ono większe od 1. Gdy tak się dzieje, to podmieniamy wspomniane minNWD i podbijamy licznik długości ciągu o 1. W innym przypadku oznacza to, że nasz podciąg już nie ma dalej wspólnego NWD z kolejną liczbą, więc zapisujemy trzy parametry końcowe i przerywamy działanie drugiej pętli, wracając tym samym do kolejnej. 

Pozostaje wyrzucić na ekran wynik i gotowe. I ja wiem, że jest to bardzo skomplikowane na pierwszy rzut oka, ale z doświadczenia wiem, że analizując tego typu zadanie, rozwiązanie samo się zaczyna nasuwać. Wszystko to wymaga tylko i wyłącznie praktyki oraz wiedzy dotyczącej działania algorytmów. Pomysł przychodzi sam! 

Zachęcam gorąco do samodzielnej analizy kodu, bo bez tego nie zrozumiesz co tu się właściwie dzieje.

Implementacja
with open('liczby.txt') as f:
    lines = f.readlines()


def NWD(a, b):
    if b > 0:
        return NWD(b, a % b)
    return a


def searchMaxLen():
    allLength = 0
    firstElem = 0
    returnedNWD = 0
    length = len(lines)

    for i in range(length - 1):
        minNWD = lines[i]
        first = lines[i]
        k = 1

        for j in range(i + 1, length):
            n = NWD(int(minNWD), int(lines[j]))

            if n > 1:
                minNWD = n
                k += 1

            if n == 1 or length - 1 == j:
                if k > allLength:
                    returnedNWD = minNWD
                    firstElem = first
                    allLength = k
                break


    print(str(firstElem).strip() + ' ' + str(allLength) + ' ' + str(returnedNWD))


searchMaxLen()

Matura rozszerzona z informatyki — Zadanie 5


Czas na zadanie typu, więcej opisu i analizowania niż rozwiązywania. Po przeczytaniu wstępu mamy informacje, że będziemy bazować na pliku, który jest wypełniony szeregiem danych. Plik ten zawiera rozdzielone znakiem średnika kolumny takie jak Dzień pomiarów, temperatura, Opad, Kategoria i wielkość chmur. Chmury mają dwie kategorie oraz pięć wielkości. Łącznie na niebie możemy mieć 10 różnych rodzajów chmur lub jedenasta możliwość to niebo bezchmurne.

Z opisu wynika również, że 200 ostatnich pomiarów nie zarejestrowało rodzaju i wielkości chmur. Na koniec jeszcze krótka informacja, w jaki sposób mamy przedstawić wynik. Warto się trzymać wytycznych i odpowiednio nazywać pliki. 

Pora przejść do zadań. Idealnie byłoby te dane wrzucić do bazy danych, wtedy w prosty sposób moglibyśmy pracować na danych. Warto też rozważyć opcję pracy na pliku Excel. Ja wybieram opcję zarówno pracy z arkuszem kalkulacyjnym jak i bazą danych z pliku tekstowego.

Po uruchomieniu Libre Office wybieram opcję baza danych i w oknie poniżej wybieram Połącz z istniejącą bazą danych z Tekstu.

Wybranie bazy danych w Libre Office z tekstu.
Rysunek 1. Wybranie bazy danych w Libre Office z tekstu.

 

Następnie przechodzę dalej i ustawiam kilka rzeczy. Po pierwsze, folder, gdzie znajduje się plik pogoda.txt. Dodatkowo wybieram, że czytam z pliku txt, a nie csv. Ustalam, że separatorem jest znak średnika, a liczby dziesiętne mają znak przecinka zamiast kropki.

Dalsza konfiguracja ustawień bazy danych z pliku.
Rysunek 2. Dalsza konfiguracja ustawień bazy danych z pliku.

Klikamy przycisk Zakończ, zapisujemy na dysku bazę danych i możemy cieszyć się tabelą pogoda, a w niej szeregiem danych, na których będziemy pracować.

Utworzona baza danych z tabelą pogoda.
Rysunek 3. Utworzona baza danych z tabelą pogoda.

Po tak przygotowanym środowisku możemy rozpocząć pracę nad naszymi zadaniami.

Zadanie 5.1

Czas na małą rozgrzewkę. Naszym zadaniem będzie napisanie małego zapytania, które zwróci nam informacje o wszystkich dniach, które miały temperaturę 20 stopni lub większą i opady mniejsze bądź równe 5 mm.

Aby to zrobić, tworzymy nową kwerendę, wybierając Kwerendy -> Utwórz kwerendę SQL.

Utworzenie nowej kwerendy.
Rysunek 4. Utworzenie nowej kwerendy.

Piszemy jedno zapytanie, które policzy nam dni. Używamy do tego funkcji Count(*). Normalnie nie jest zalecane używanie „gwiazdki” tylko na przykład 0, lecz Libre Office ma problem z tego typu wywołaniem. Zapytanie uruchamiamy, klikając przycisk F5.

Jak widać, wynik to 63.

Zapytanie rozwiązujące zadanie pierwsze.
Rysunek 5. Zapytanie rozwiązujące zadanie pierwsze.

Zadanie 5.2

Czas na drugie zadanie, teraz na coś odrobinę trudniejszego. Musimy znaleźć taki ciąg dni, w których temperatura z dnia na dzień rosła. Interesuje nas najdłuższy taki okres czasu i numer pierwszego dnia od wzrostu i numer dnia ostatniego.

Ważna uwaga jeszcze, widzimy, że nie bierzemy dnia „zerowego”, od którego temperatura zaczęła rosnąć. Widać to na przykładzie w treści zadania. Tu posłużymy się arkuszem kalkulacyjnym.

Otwieramy arkusz, następnie klikamy Plik -> Otwórz i wybieramy plik pogoda.txt. Teraz czas podzielić plik na kolumny po odpowiednim separatorze. Ważne, by odznaczyć przecinek, ponieważ rozdzieli nam to liczby dziesiętne na liczby całkowite i te po przecinku. 

Uruchomienie arkusza kalkulacyjnego i wczytanie wartości z tekstu.
Rysunek 6. Uruchomienie arkusza kalkulacyjnego i wczytanie wartości z tekstu.

Po uruchomieniu się arkusza dodaję nową kolumnę F o nazwie zadanie 52. Warto też pierwszy wiersz zrobić pusty, tak by ułatwić sobie obliczenia. W nowej kolumnie użyję funkcji JEŻELI, w której sprawdzę, czy wartość z aktualnej komórki B jest większa od wartości z poprzedniej komórki. Jeżeli tak, to dosumuję jedynkę, w innym przypadku wstawiam zero.

Funkcja JEŻELI, która pomoże zbudować ciąg kolejnych dni.
Rysunek 7. Funkcja JEŻELI, która pomoże zbudować ciąg kolejnych dni.

Dalej w komórce F1 wykonam funkcję MAKS, która z całej kolumny F wskaże nam miejsce, gdzie kończy się największy ciąg. Pod tym numerem będzie kryć się więc dzień z największą temperaturą w ciągu. Cofamy się w tym ciągu do jedynki i wyczytujemy numer dnia, w którym ten ciąg się zaczął. Odpowiedzią więc jest to, że temperatury zaczęły rosnąć 448 dnia, a skończyły rosnąć dnia 455.

Funkcja MAKS, która pokazuje ostatni dzień, w którym temperatury przestały rosnąć.
Rysunek 8. Funkcja MAKS, która pokazuje ostatni dzień, w którym temperatury przestały rosnąć.

Zadanie 5.3

Zadanie trzecie to praca z danymi i prezentacja tych danych na wykresie. Warto zwrócić uwagę, że będziemy bazować tylko na pierwszych trzystu rekordach, nie zaś na całej tabeli. W tym celu zaznaczam te rekordy i kopiuję do osobnego arkusza.

Kluczem w całym zadaniu jest skonfigurowanie poprawnie tabeli przestawnej. Aby to zrobić, zaznaczam wszystkie rekordy i klikam Dane -> Tabela przestawna -> Wstaw lub edytuj. 

Teraz ważne, by wstawić to, co nas interesuje. Oczywiście w Pola wierszy lądują Kategorie chmur i ich wielkość a w Pola danych wstawimy Opad, ważne by była to wartość średnia opadu.

Tabela przestawna grupująca dane.
Rysunek 9. Tabela przestawna grupująca dane.

Po kliknięciu przycisku OK pojawi się nowa zakładka, a w niej pogrupowane ładnie dane. Zróbmy zaokrąglenie kolumny Średnia — opady do dwóch miejsc po przecinku i dopiszmy pomocnicze nazwy zmiennych od C1 do C5 oraz od S1 do S5. 

Przygotowanie tabeli przestawnej do zbudowania wykresu.
Rysunek 10. Przygotowanie tabeli przestawnej do zbudowania wykresu.

Pozostaje już kolumnę C i D wybrać oraz kliknąć opcję tworzenia nowego wykresu. Wykres zatytułujemy jako Średnia opadów, oś X to Typ chmur, oś Y natomiast to Średnia. 

Poprawny wykres.
Rysunek 11. Poprawny wykres.

Zadanie 5.4

Czwarta część zadania to fajny przykład na możliwości pracy ze zbiorami danych. Musimy na podstawie pierwszych 300 dni i obserwacji profesora zająć się uzupełnieniem ostatnich 200 rekordów, a następnie oszacować, jak wygląda poprawność obserwacji profesora przez pierwsze 300 dni, uwzględniając kategorie i wielkość chmur. Typ tego zadania to tak zwana symulacja.

Z zadania wynikają następujące rzeczy. Jeżeli dzień był bezchmurny, to kolejnego dnia pojawia się chmura na poziomie 1 i utrzymuje się tak przez trzy dni, aż podskoczy o 1. Taka sytuacja ma miejsce do piątki włącznie. Piątka znika w momencie, gdy spadnie z niej więcej niż 20 mm deszczu. Wtedy znów mamy bezchmurne niebo i cykl się powtarza.

Zapis takiej formuły w arkuszu jest mocno skomplikowany i kilkukrotnie pomyliłem się przy jego tworzeniu. Ostatecznie wychodzi coś takiego:

=JEŻELI(G5=0;1;
                           JEŻELI(I(G5=5;C5>=20);0;
                                                                        JEŻELI(I(G5=G3;G5<5);G5+1;G5)))

Musisz to sobie rozłożyć na czynniki pierwsze i pogrupować informacje zgodnie z treścią zadania. To, co osiągniemy tą formułą widać bardzo ładnie na rysunku poniżej. W kolumnie G będziemy mieć określoną wielkość chmur w zależności od warunków.

Działanie formuły i uzupełniona dzięki niej kolumna z wielkością chmury.
Rysunek 12. Działanie formuły i uzupełniona dzięki niej kolumna z wielkością chmury.

Czas przejść do określenia, czy chmura jest typu C czy S. Zależy to od temperatury, jeżeli jest ona nie mniejsza od 10 w dniu pojawienia się chmury o wielkości 1, to będzie to typ C, w innym przypadku S. 

Musimy znów pobawić się z warunkami JEŻELI. W przypadku gdy kolumna, którą analizujemy, czyli G4 jest równa 0, czyli bezchmurna, wtedy zostawiamy bezchmurne niebo, w innym przypadku gdy dzień poprzedni, czyli G3 nie był bezchmurny, to wstawiamy ten typ kolumny z H3. Jeżeli jednak poprzedniego dnia było zero, to patrzymy na temperaturę. Jeżeli temperatura dziś jest większa, bądź równa 10 to wstawiamy C, innym razem S.

Tu też polecam mocno przeanalizować na własnym przykładzie!

=JEŻELI(G4=0;0;
                              JEŻELI(G3 <> 0;H3;
                                                                JEŻELI(B4 >= 10; „C”;”S”)))
Określenie typu chmur.
Rysunek 13. Określenie typu chmur.

Podpunkty

Mamy surowe dane, czas więc zająć się nimi w punktach a, b i c. Zacznijmy od przekopiowania kolumny Wielkość i zróbmy z niej tabelę przestawną.

Wygląd tabeli przestawnej zliczającej poszczególne dni.
Rysunek 14. Wygląd tabeli przestawnej zliczającej poszczególne dni.

Po takim pogrupowaniu, gdzie polem wiersza będą wielkości chmur i w Pola danych posumujemy je. Tabela przestawna będzie wyglądać następująco.

Tabela przestawna pokazująca wynik sumowania każdej wielkości chmur.
Rysunek 15. Tabela przestawna pokazująca wynik sumowania każdej wielkości chmur.

Punkt a mamy dokończony, czas na dwa kolejne. Są one analogiczne, czyli dotyczą tego samego zagadnienia. Mamy sprawdzić, które wielkości i rodzaje chmur dla pierwszych 300 dni zgadzają się z teorią profesora. Wracamy więc do głównego arkusza i zaczynamy znów pisać funkcję JEŻELI dla jednej i drugiej sprawdzanej wartości.

=JEŻELI(G3=E3;1;0)

Dzięki tak zapisanej funkcji po prostu sprawdzimy, czy symulowana wartość typu i wielkości równa się z rzeczywistą. Przeciągamy do końca i sumujemy wartości, by ocenić, ile z nich jest poprawnych.

Jak widać, wielkości chmur były niemal bezbłędne, bo na 300 dni, popranie oszacowano 296 dni. W przypadku typu było trochę gorzej, bo na 300 dni 286 było poprawnie oszacowane.

To kończy zadanie numer 5.

Matura rozszerzona z informatyki — Zadanie 6

Matura rozszerzona z informatyki – maj 2019 zadanie 6

Czas na ostatnie zadanie z tego arkusza egzaminacyjnego. Pierwsze pięć poszło dość gładko. Zobaczymy, co pokaże nam ostatnie.

Z informacji wynika, że dostaliśmy trzy pliki, które zawierają informacje na temat oferty perfum. Nazwy plików już mogą nam zasugerować, że będziemy operować na bazie danych. W przypadku tych plików separatorem nie będzie średnik, lecz tabulator. Struktura nie jest zbyt skomplikowana, gdzie główną tabelą jest tabela perfumy, która posiada klucz obcy do tabeli marka. Dodatkowo tabela skład posiada klucz obcy do tabeli perfumy. 

Aby rozpocząć pracę, musimy przygotować sobie bazę danych. Wczytajmy trzy tabele z odpowiedniego katalogu, tak samo jak w przypadku zadania piątego, jednak separatorem danych będzie tabulator.

Baza danych z trzema tabelami.
Rysunek 16. Baza danych z trzema tabelami.

Mając utworzoną bazę, możemy zaczynać pracę!

Zadanie 6.1

Zadanie numer jeden to standardowo coś na rozgrzewkę. Musimy podać listę nazw perfum, które zawierają jeden ze składników, w tym przypadku „absolut jasminu”.

Wystarczy uruchomić zapytanie, które pobierze nam kolumnę nazwa_p z tabeli perfumy, gdzie nazwa_skladnika równa się absolut jasminu. Jak ktoś pracował, chociaż chwilę z bazą danych to takie zapytanie zrobi w 30 sekund.

SELECT p.nazwa_p FROM perfumy p
JOIN sklad s on s.id_perfum = p.id_perfum 
WHERE s.nazwa_skladnika = 'absolut jasminu'

Wynikiem zapytania będą trzy nazwy — Oyal Priather, Ologne D’oud oraz Ueiques FleuE.

Zadanie 6.2

Zadanie drugie wymaga napisania zapytania o trochę większym poziomie zaawansowania. Po pierwsze musimy podać nazwę rodziny, nazwę perfum oraz najniższą cenę. Jak widzimy, będziemy operować tylko na tabeli głównej perfumy. 

W pracy z tabelami i grupowaniem trzeba zawsze pamiętać o robieniu różnych sztuczek. W naszym zadaniu musimy stworzyć podzapytanie, które będzie pogrupowane po rodzinie zapachów i będzie zawierało dla tej rodziny najniższą wartość. Osiągniemy to dzięki funkcji min().

Następnie w głównym zapytaniu dociągamy jeszcze nazwę i w warunku ograniczamy się tylko do wyników, których cena jest minimalna. Poniższe zapytanie wygeneruje 18 rekordów z poprawnymi odpowiedziami.

SELECT x.rodzina_zapachow, p.nazwa, p.cena 
FROM perfumy AS p
JOIN (select rodzina_zapachow, min(cena) as minimalna FROM perfumy GROUP BY rodzina_zapachow) AS x
WHERRE p.cena = x.minimalna

Zadanie 6.3

Zadanie trzecie jest bardzo podobne do drugiego. Również zastosujemy tu podzapytanie, lecz złożone z dwóch tabel. Celem naszym w tym przypadku znalezienie wszystkich marek, które w składzie swoich perfum nie zawierają składnika, który to składnik nie ma w swojej nazwie wyrazu ‚paczula’.

Zacznijmy od podzapytania. Poprośmy bazę danych, by zwróciła nam z tabeli perfumy id_marka., lecz tylko te perfumy, które w składzie mają słowa ‚paczula’. Następnie tego podzapytanie używamy z tabelą marka, wykluczając takie ID, które posiadają slowo ‚paczula’. Na koniec wyrzucamy na ekran nazwę marki i używamy klauzuli ORDER BY po to, by posortować od A do Z szukane nazwy marek.

Będzie ich pięć. 

SELECT m.nazwa_m 
FROM marki m
WHERE m.id_marki NOT IN
	(SELECT DISTINCT p.id_marki 
	FROM perfumy p
	JOIN sklad s ON s.id_perfum = p.id_perfum
	WHERE s.nazwa_skladnika like '%paczula%')
ORDER BY m.nazwa_m

Zadanie 6.4

Kolejne zadanie bazuje na tym, by policzyć nowe ceny, które będą obniżone o 15% od ceny standardowej. Ważne jest to, by obniżyć ceny tylko dla konkretnej marki o nazwie „Mou De Rosine” i dla konkretnej rodziny „orientalno-drzewnej”. Dodatkowo mają zostać posortowane według ceny.

Cenę wystarczy przemnożyć przez 0.85 i przez tę wartość posortować. Oczywiście warunek musi zawierać szukaną nazwę marki i rodzinę zapachów. Chcę tu nadmienić, że w SQL musimy uważać na wielkość liter podczas porównywania.  „Mou De Rosine” to nie to samo co „mou de rosine”.

Wynik zapytania zwróci 8 rekordów.

SELECT m.nazwa_m, (p.cena * 0.85) nowa_cena
FROM perfumy p
JOIN marki m ON mid_marki = p.id_marki
WHERE p.rodzina_zapachow = 'orientalno-drzewna'
AND m.nazwa_m = 'Mou De Rosine'
ORDER p.cena * 0.85

Zadanie 6.5

Czas na ostatnie zadanie w tej maturze. Z mojej perspektywy jest to jedno z łatwiejszych podzadań z 6 zadania. Najważniejszą częścią tego zadania będzie podzapytanie, które wydobędzie nam marki i rodziny zapachów, które pogrupowane zwrócą tylko jeden wiersz. Aby tego dokonać, musimy zastosować słowo kluczowe distinct.

Następnie w zapytaniu głównym pogrupować zbiory i użyć słowa kluczowego having, które pokaże nam tylko takie perfumy, które należą do jednej rodziny zapachów.

Będzie ich pięć.

SELECT m.nazwa_m, x.rodzina_zapachow
FROM 	
	(
		SELECT DISTINCT p.id_marki, p.rodzina_zapachow 
		FROM perfumy p
	) AS x
JOIN marki m ON m.id_marki = x.id_marki
GROUP BY x.id_marki
HAVING COUNT(*) = 1
	

Na koniec zadania 6 powiem Ci jedną rzecz. Zapytania, które były pisane powyżej, są standardowymi, jakie się wykonuje w codziennej pracy z bazami danych. Matura taka i takie ćwiczenia z bazami danych to też dobry trening przed rozmową o pracę!

Matura rozszerzona z informatyki -Podsumowanie

Dobrnęliśmy do końca. Matura rozszerzona z informatyki to najdłuższy wpis na tym blogu i jestem z niego szczególnie dumny. Robiłem podejście do tej matury jakiś czas temu w formie testu własnych umiejętności i osiągnąłem wynik na poziomie 85%-90%. To, co mnie zgubiło to braki w wiedzy na temat sieci, problemy z niektórymi zagadnieniami w arkuszu kalkulacyjnym i drobny błąd w działaniu matematycznym w jednym ze skryptów — wynikał on z pośpiechu.

100% jest jak najbardziej do osiągnięcia, ale trzeba na serio mocno się przyłożyć. Ja posiadam kilka lat komercyjnego doświadczenia w programowaniu, jestem w trakcie studiów i do tego prowadzę bloga, gdzie zajmuję się między innymi algorytmami, więc wiedza ta jest u mnie na porządku dziennym. Dla osób rozpoczynających przygotowania do matury informatyki zalecam co najmniej 6-miesięczną naukę, z naciskiem na algorytmy, bazy danych i podstawy informatyki takie jak systemy liczbowe.

Matura rozszerzona z informatyki — maj 2019 pojawi się również niebawem na moim kanale na YouTube, więc zachęcam do subskrybowania!

A teraz na koniec proponuję Ci zakupić książki, które jeszcze bardziej poprawią Twoje skille jeżeli chodzi o programowanie.

PS. Będę wdzięczny za komentarze pod tym postem!

PS2. Czeka też na Ciebie prezent. Wystarczy, że zapiszesz się na Newsletter poniżej!

PS3. Dołącz do naszej grupy na Facebook!

Subskrybuj

Zapisz się na Newsletter, odbierz NAGRODĘ w postaci e-booka z 10 omówionymi algorytmami pojawiającymi się w pytaniach podczas REKRUTACJI..

Dodatkowo otrzymuj co niedzielę informacje na temat nowych wpisów, wiadomości ze świata IT i matematyki oraz ciekawych wydarzeniach. Nie przegap i dołącz już dziś do 959 osób!.
Autor

👨‍💻 .NET and Python programming passionate 🏦 Digtial Banking Solutions 🎓 Student 📊 Psychology 📚 Bookworm 🏠 Warsaw

4 komentarze

  1. Maturę z rozszerzonej informatyki zdawałem w 2018 i byłem jednym z dwóch uczniów na całą szkołę. Był to jedny egzamin do którego się przygotowywałem i z perspektywy czasu wiem że jedyny który tak naprawdę przyniósł mi jakąkolwiek przydatną wiedzę. Smutne jest to, że nie jest to zbyt poważnie traktowany egzamin w szkołach.

      • Zdobyłem 68%, przygotowywałem się głównie w domu. Z dnia egzaminu wspominam jedną śmieszną sytuację. Wchodzimy na salę gdzie stały rzekomo przygotowane komputery trochę wcześniej niż zaplanowano, mieliśmy sprawdzić czy wszystko się uruchamia i okazuje się że nie ma zainstalowanego visual studio. Szkoła nie posiadała żadnego instalatora a ściągnięcie 8gb przy 1mb łączu by było niemożliwe. Użyliśmy code blocks który był zainstalowany już, jednak to już wymagało wniesienia korekty w złożoną deklarację maturalną, dosłownie na minuty przed rozpoczęciem egzaminu 🙂 Dla osoby która zaczyna naukę informatyki na poważnie, taki egzamin moim zdaniem jest świetnym pomysłem. Przedtem klikałem sobie jakieś darmowe kursy z programowania w javascripcie czy php jednak dopiero nauka c++ dała mi wyobrażenie na temat typów danych, strumieni i tego ile jeszcze muszę się uczyć 😉 Bardzo dobry wstęp do programowania, który miło wspominam

Napisz komentarz

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.