Przeczytaj
Zadanie 1. Piksele
Zadanie zostało opracowane przez Centralną Komisję Egzaminacyjną i pojawiło się na egzaminie maturalnym z informatyki w maju 2017 roku (poziom rozszerzony, egzamin w tzw. nowej formule). Cały arkusz można znaleźć na stronie internetowej CKE. Omówimy tu rozwiązania dwóch podpunktów tego zadania.
W pliku dane.txt znajduje się 200 wierszy. Każdy wiersz zawiera 320 liczb naturalnych z przedziału od 0 do 255, oddzielonych znakami pojedynczego odstępu (spacjami). Przedstawiają one jasności kolejnych pikselipikseli czarno‑białego obrazu o wymiarach 320 na 200 pikseli (od 0 – czarny do 255 – biały).
Napisz program(y), który(e) da(dzą) odpowiedzi do poniższych zadań. Odpowiedzi zapisz w pliku wyniki6.txt, a każdą odpowiedź poprzedź numerem oznaczającym odpowiednie zadanie.
Uwaga: plik przyklad.txt zawiera dane przykładowe spełniające warunki zadania (obraz ma takie same rozmiary). Odpowiedzi dla danych z pliku przyklad.txt są podane pod poleceniami.
Plik przyklad.txt:
Plik dane.txt:
Rozwiązanie przedstawiamy w formie pseudokodu. Twoim zadaniem będzie jego implementacja w wybranym języku programowania dostępnym na egzaminie maturalnym: C++, Java lub Python.
Zadanie 1.1
Podaj jasność najjaśniejszego i jasność najciemniejszego piksela.
Dla danych z pliku przyklad.txt wynikiem jest 255 (najjaśniejszy) i 0 (najciemniejszy).
Do oceny oddajesz:
plik
wyniki6.txtzawierający odpowiedź (numer zadania, wartości najjaśniejszego i najciemniejszego piksela, zapisane w osobnych liniach),plik(i) z komputerową realizacją zadania (kodem programu).
Rozwiąż zadanie dla kompletnych danych wejściowych załączonych powyżej. Rozwiązanie przedstaw w wybranym języku programowania, dostępnym na egzaminie maturalnym: C++, Java lub Python. Zadbaj o prawidłowe wczytanie danych z pliku tekstowego do programu. Odpowiedź do zadania znajdziesz w osobnym pliku, umieszczonym pod omówieniem rozwiązania.
Rozwiązanie
Zaczniemy od wczytania danych z pliku do tablicy dwuwymiarowej dane[200][320] (C++, Java) lub listy list (Python).
Ze względu na tematykę materiału wczytywanie danych z pliku zostanie zaprezentowane z użyciem języków programowania: C++, Java i Python, zamiast w pseudokodzie.
Przedstawione fragmenty kodu pokazują, jak wczytać dane z podanego pliku wiersz po wierszu i zmienić je na liczby całkowite. W każdym rozwiązaniu dodaliśmy instrukcje wypisujące wczytane liczby na standardowym wyjściu.
W języku C++ najprostszym sposobem na odczytanie liczb z kolejnych wierszy podanego pliku jest użycie operatora przekierowania wejścia >>. W zagnieżdżonej pętli for odczytujemy z każdego wiersza 320 liczb.
W językach Java i Python dane z pliku czytamy wiersz po wierszu, liczby z każdego odczytanego wiersza otrzymujemy w postaci tablicy lub listy zwracanej za pomocą funkcji split(), która dzieli podany ciąg znaków za pomocą podanego separatora.
W języku Java możemy skorzystać z klasy Scanner lub klasy BufferedReader, która buforuje odczytywane dane i jest wydajniejsza, kiedy plik odczytujemy wiersz po wierszu.
W języku Python nie używa się tablic o określonym z góry rozmiarze, struktury służące do przechowywania wielu elementów, np. listy, są dynamiczne. W podanym niżej rozwiązaniu ciągi znaków zwrócone przez metodę split() przekształcamy na liczby całkowite w wyrażeniu listowym, a uzyskaną listę zapisujemy w liście dane.
Znalezienie piksela o najmniejszej wartości (najciemniejszego) i o największej wartości (najjaśniejszego)
Najpierw ustalamy początkowe wartości zmiennych MIN i MAX. W obu przypadkach będzie to wartość pierwszego elementu tablicy.
Następnie iterujemy po tablicy dwuwymiarowej dane[200][320] i w przypadku, gdy znajdziemy wartość większą od wartości MAX, nadpisujemy wartość zmiennej MAX, nadając jej wartość równą dane[i][j].
Szukanie najciemniejszego piksela jest bardzo podobne. Sprawdzamy, czy aktualnie iterowany element tablicy dwuwymiarowej jest mniejszy od MIN – jeżeli tak, nadpisujemy wartość zmiennej MIN (nadajemy jej wartość dane[i][j])
Oto cały pseudokod:
Schemat punktowania
2 pkt – za prawidłową odpowiedź, w tym:
1 pkt – za podanie wartości najjaśniejszego piksela
1 pkt – za podanie wartości najciemniejszego piksela
0 pkt – za odpowiedź błędną albo za brak odpowiedzi
Poprawna odpowiedź
Wartość najjaśniejszego piksela 221.
Wartość najciemniejszego piksela 7.
Prawidłowa odpowiedź do zadania 1.1 dla danych zapisanych w pliku dane.txt tekstowym znajduje się w załączniku:
Zadanie 1.2
Podaj, ile wynosi najmniejsza liczba wierszy, które należy usunąć, żeby obraz miał pionową oś symetrii. Obraz ma pionową oś symetrii, jeśli w każdym wierszu i‑ty piksel od lewej strony przyjmuje tę samą wartość, co i‑ty piksel od prawej strony, dla dowolnego 1 ≤ i ≤ 320. Dla danych z pliku przyklad.txt wynikiem jest 3.
Do oceny oddajesz:
plik
wyniki6.txtzawierający odpowiedź (numer zadania i liczba wierszy do usunięcia w osobnych wierszach, dopisane do pliku utworzonego w zadaniu 1.1),plik(i) z komputerową realizacją zadania (kodem programu).
Rozwiąż zadanie dla kompletnych danych wejściowych, znajdujących się w pliku załączonym powyżej. Rozwiązanie przedstaw w wybranym języku programowania, dostępnym na egzaminie maturalnym: C++, Java lub Python. Zadbaj o prawidłowe wczytanie danych z pliku tekstowego do programu. Odpowiedź do zadania znajdziesz w osobnym pliku umieszczonym pod omówieniem rozwiązania.
Rozwiązanie
Operujemy na tablicy dwuwymiarowej dane[200][320], do której zostały zapisane dane z pliku tekstowego (wczytanie danych przedstawione jest w rozwiązaniu zadania 1.1).
Deklarujemy zmienną doUsuniecia, która będzie zliczać linie niespełniające kryterium pionowej osi symetrii. Jako wartość początkową nadajemy jej wartość 0.
Następnie w pętli zewnętrznej przeglądamy kolejne wiersze tablicy dwuwymiarowej dane[200][320]. W pętli wewnętrznej sprawdzamy symetryczność analizowanego wiersza pikseli. Oznacza to, że musimy sprawdzić symetryczność par pikseli równoodległych od badanej pionowej osi symetrii, czyli zweryfikować, czy te wiersze są palindromami. Liczba par do sprawdzenia jest równa połowie rozmiaru wiersza, co wyznacza również ograniczenie wartości iteratora pętli.
element o indeksie 0 z elementem o indeksie 319;
element o indeksie 1 z elementem o indeksie 318;
element o indeksie 3 z elementem o indeksie 317;
...
element o indeksie 159 z elementem o indeksie 160.
Jeżeli wykryjemy, że elementy porównywane nie są równe, oznacza to, że dana para zaburza oś symetrii i cały wiersz jest do usunięcia. Wówczas dokonujemy inkrementacjiinkrementacji zmiennej doUsuniecia oraz wychodzimy z pętli (ponieważ w danym wierszu nie ma już potrzeby, aby sprawdzać inne wartości pikseli).
Schemat punktowania
2 pkt – za poprawną odpowiedź
0 pkt – za odpowiedź błędną lub brak odpowiedzi
Uwaga: Nie przyznaje się 1 pkt.
Poprawna odpowiedź
149
Dla zainteresowanych
W sytuacji, kiedy nie znamy liczby wierszy oraz liczby liczb zapisanych w poszczególnych wierszach pliku wejściowego do przechowania odczytanych danych, używamy struktur dynamicznych.
Podane w zadaniu 1.1 rozwiązanie dla języka Python można wykorzystać również w omawianym przypadku.
W języku C++ możemy skorzystać z tablic typu vector. W podanym niżej kodzie zawartość pliku odczytujemy wiersz po wierszu. Każdy odczytany wiersz przekształcamy na strumień wejściowy za pomocą konstruktora istringstream. Z otrzymanego strumienia, podobnie jak z pliku, za pomocą operatora przekierowania wejścia >> odczytujemy wszystkie liczby.
W języku Java jedną z możliwości jest wykorzystanie klasy List, dzięki której możemy stworzyć strukturę podobną do wykorzystanej wyżej listy list w języku Python.
Odczytane wiersze przy użyciu metody split() dzielimy na ciągi znaków (separatorem jest znak spacji) zwrócone w tablicy, którą przekształcamy na strumień za pomocą metody stream() klasy Arrays. Następnie korzystamy z metody map(), aby każdy element strumienia przekształcić na liczbę całkowitą. Z uzyskanej tablicy liczb całkowitych za pomocą metody collect() tworzymy listę, którą dodajemy przy użyciu metody add() do listy dane.
Przekierowanie standardowego wejścia i wyjścia
Oprócz przedstawionych rozwiązań możliwe jest również przekierowanie standardowego wejścia i wyjścia na wskazane pliki podczas uruchamianiu kodu z poziomu linii poleceń. Operatorem przekierowania standardowego wejścia jest operator <, natomiast operatorem przekierowania standardowego wyjścia jest operator >.
Język C++
Podany niżej kod jest prawie identyczny z omówionym wyżej rozwiązaniem wykorzystującym dynamiczne tablice. Zmiany polegają na usunięciu kodu obsługującego strumień pliku i użyciu standardowego strumienia wejścia w instrukcji: getline(cin, wiersz).
Sprawdzenie działania powyższej wersji kodu możliwe jest po wykonaniu w terminalu następujących poleceń:
Pierwsze polecenie kompiluje kod i buduje plik wykonywalny (w systemach Linux rozszerzenie .exe jest opcjonalne). Drugie polecenie jako strumień wejścia wskazuje plik dane.txt, a jako strumień wyjścia, do którego wypisywane będą komunikaty np. funkcji cout(), plik wyniki.txt.
Język Java
Program wykorzystujący struktury dynamiczne wymaga minimalnych zmian, aby dane czytane były z przekierowanego wejścia. Wystarczy, że zmienną plik typu BufferReader utworzymy jako obiekt klasy InputStreamReader, której konstruktorowi przekazujemy standardowy strumień wejścia System.in:
Polecenia niezbędne do przetestowania powyższej wersji wydajemy w terminalu:
Pierwsze polecenie kompiluje kod, drugie uruchamia program przekierowując standardowe wejście na plik dane.txt, a wyjście na plik wyniki.txt. Do tego ostatniego pliku trafią wszystkie komunikaty z instrukcji System.out.print() lub System.out.println().
Język Python
W języku Python można dane czytać ze standardowego strumienia wejścia sys.stdin, jednak kiedy dane znajdują się w pliku, lepiej użyć modułu fileinput i metody input():
Polecenie uruchomienia skryptu z wejściem przekierowanym na plik dane.txt, a wyjściem na plik wyniki.txt wydajemy w terminalu:
W systemie Windows po standardowej instalacji interpreter Pythona wywoływany jest przez polecenie python, a nie python3.
Do pliku wyniki.txt zapisane zostaną wszystkie komunikaty z instrukcji print().
Słownik
zwiększenie danej wartości o jeden
prosta, względem której dane dwie figury są symetryczne
(ang. pixel) najmniejsza jednolita część obrazu wyświetlanego na ekranie monitora, drukowanego lub wyświetlanego przy użyciu specjalistycznych urządzeń (aparatów cyfrowych i tym podobnych)