R1PE57JCHTD5V
Obrazek przedstawia dane zgromadzone w plikach na dyskach oraz w chmurze

I_R_W13A_M07_JAVA Pliki na maturze

Grafika wygenerowana przez sztuczną inteligencją Leonardo.ai
Źródło: domena publiczna.

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 pikseli 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:

R11dFVCOytFZv

Przycisk do pobrania pliku TXT z treścią zadania.

Plik TXT o rozmiarze 126.21 KB w języku polskim

Plik dane.txt:

R1SoEVmFcg11G

Przycisk do pobrania pliku TXT z treścią zadania.

Plik TXT o rozmiarze 223.62 KB w języku polskim

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.txt zawierają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).

Ważne!

Ze względu na tematykę materiału wczytywanie danych z pliku zostanie zaprezentowane z użyciem języków programowania: C++, JavaPython, 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 Java 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.

Linia 1. import java kropka io kropka BufferedReader średnik. Linia 2. import java kropka io kropka FileReader średnik. Linia 3. import java kropka io kropka IOException średnik. Linia 4. import java kropka util kropka Arrays średnik. Linia 6. public class Main otwórz nawias klamrowy. Linia 7. otwórz nawias ostrokątny code style znak równości cudzysłów white minus space dwukropek pre średnik cudzysłów data minus inline zamknij nawias ostrokątny public static void main otwórz nawias okrągły String otwórz nawias kwadratowy zamknij nawias kwadratowy args zamknij nawias okrągły throws IOException otwórz nawias klamrowy. Linia 8. prawy ukośnik prawy ukośnik 2 minus wymiarowa tablica. Linia 9. int otwórz nawias kwadratowy zamknij nawias kwadratowy otwórz nawias kwadratowy zamknij nawias kwadratowy dane znak równości new int otwórz nawias kwadratowy 200 zamknij nawias kwadratowy otwórz nawias kwadratowy 320 zamknij nawias kwadratowy średnik. Linia 10. BufferedReader plik znak równości new BufferedReader otwórz nawias okrągły new FileReader otwórz nawias okrągły cudzysłów dane kropka txt cudzysłów zamknij nawias okrągły zamknij nawias okrągły średnik. Linia 11. String wiersz średnik. Linia 13. for otwórz nawias okrągły int i znak równości 0 średnik i ampersant lt średnik 200 średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy. Linia 14. wiersz znak równości plik kropka readLine otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 15. String otwórz nawias kwadratowy zamknij nawias kwadratowy liczby znak równości wiersz kropka split otwórz nawias okrągły cudzysłów cudzysłów zamknij nawias okrągły średnik. Linia 16. for otwórz nawias okrągły int j znak równości 0 średnik j ampersant lt średnik 320 średnik j plus plus zamknij nawias okrągły. Linia 17. prawy ukośnik prawy ukośnik odczytywanie liczb z wiersza. Linia 18. dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy znak równości Integer kropka parseInt otwórz nawias okrągły liczby otwórz nawias kwadratowy j zamknij nawias kwadratowy zamknij nawias okrągły średnik. Linia 19. zamknij nawias klamrowy. Linia 20. plik kropka close otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 22. prawy ukośnik prawy ukośnik wypisanie odczytanych liczb. Linia 23. for otwórz nawias okrągły int i znak równości 0 średnik i ampersant lt średnik 200 średnik i plus plus zamknij nawias okrągły otwórz nawias klamrowy. Linia 24. for otwórz nawias okrągły int j znak równości 0 średnik j ampersant lt średnik 320 średnik j plus plus zamknij nawias okrągły. Linia 25. System kropka out kropka print otwórz nawias okrągły dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy plus cudzysłów cudzysłów zamknij nawias okrągły średnik. Linia 26. System kropka out kropka println otwórz nawias okrągły cudzysłów cudzysłów zamknij nawias okrągły średnik. Linia 27. zamknij nawias klamrowy. Linia 29. zamknij nawias klamrowy otwórz nawias ostrokątny prawy ukośnik code zamknij nawias ostrokątny. Linia 31. zamknij nawias klamrowy.

Znalezienie piksela o najmniejszej wartości (najciemniejszego) i o największej wartości (najjaśniejszego)

Linia 1. MIN ← dane otwórz nawias kwadratowy 0 zamknij nawias kwadratowy otwórz nawias kwadratowy 0 zamknij nawias kwadratowy. Linia 2. MAX ← dane otwórz nawias kwadratowy 0 zamknij nawias kwadratowy otwórz nawias kwadratowy 0 zamknij nawias kwadratowy. Linia 4. dla i znak równości 0 przecinek 1 przecinek 2 przecinek kropka kropka kropka przecinek 199 wykonuj. Linia 5. dla j znak równości 0 przecinek 1 przecinek 2 przecinek kropka kropka kropka przecinek 319 wykonuj. Linia 6. jeżeli dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy zamknij nawias ostrokątny MAX. Linia 7. MAX ← dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy. Linia 8. jeżeli dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy otwórz nawias ostrokątny MIN. Linia 9. MIN ← dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy.

Najpierw ustalamy początkowe wartości zmiennych MINMAX. 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:

Linia 1. dane otwórz nawias kwadratowy 0 kropka kropka 199 zamknij nawias kwadratowy otwórz nawias kwadratowy 0 kropka kropka 319 zamknij nawias kwadratowy. Linia 3. dla i znak równości 0 przecinek 1 przecinek 2 przecinek kropka kropka kropka przecinek 199 wykonuj. Linia 4. wczytaj kolejną linię z pliku. Linia 5. dla j znak równości 0 przecinek 1 przecinek 2 przecinek kropka kropka kropka przecinek 319 wykonuj. Linia 6. dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy ← wczytaj kolejną liczbę z linii. Linia 8. MIN ← dane otwórz nawias kwadratowy 0 zamknij nawias kwadratowy otwórz nawias kwadratowy 0 zamknij nawias kwadratowy. Linia 9. MAX ← dane otwórz nawias kwadratowy 0 zamknij nawias kwadratowy otwórz nawias kwadratowy 0 zamknij nawias kwadratowy. Linia 11. dla i znak równości 0 przecinek 1 przecinek 2 przecinek kropka kropka kropka przecinek 199 wykonuj. Linia 12. dla j znak równości 0 przecinek 1 przecinek 2 przecinek kropka kropka kropka przecinek 319 wykonuj. Linia 13. jeżeli dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy zamknij nawias ostrokątny MAX. Linia 14. MAX ← dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy. Linia 15. jeżeli dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy otwórz nawias ostrokątny MIN. Linia 16. MIN ← dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy.

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:

REAz8DjOxRzy6

Przycisk do pobrania pliku TXT z wynikiem zadania.

Plik TXT o rozmiarze 9.00 B w języku polskim

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.txt zawierają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).

Linia 1. doUsuniecia ← 0. Linia 3. dla i znak równości 0 przecinek 1 przecinek 2 przecinek kropka kropka kropka przecinek 199 wykonuj. Linia 4. k ← 319. Linia 5. dla j znak równości 0 przecinek 1 przecinek 2 przecinek kropka kropka kropka przecinek 159 wykonuj. Linia 6. jeżeli dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy ≠ dane otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy k zamknij nawias kwadratowy. Linia 7. doUsuniecia ← doUsuniecia plus 1. Linia 8. wyjdź z pętli. Linia 9. k ← k minus 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 inkrementacji 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.

W języku 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.

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.

Linia 1. import java kropka io kropka BufferedReader średnik. Linia 2. import java kropka io kropka FileReader średnik. Linia 3. import java kropka io kropka IOException średnik. Linia 4. import java kropka util kropka asterysk średnik. Linia 5. import java kropka util kropka stream kropka Collectors średnik. Linia 7. public class Main otwórz nawias klamrowy. Linia 8. otwórz nawias ostrokątny code style znak równości cudzysłów white minus space dwukropek pre średnik cudzysłów data minus inline zamknij nawias ostrokątny public static void main otwórz nawias okrągły String otwórz nawias kwadratowy zamknij nawias kwadratowy args zamknij nawias okrągły throws IOException otwórz nawias klamrowy. Linia 9. prawy ukośnik prawy ukośnik Lista list. Linia 10. List ampersant lt średnik List ampersant lt średnik Integer ampersant gt średnik ampersant gt średnik dane znak równości new ArrayList ampersant lt średnik ampersant gt średnik otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 11. BufferedReader plik znak równości new BufferedReader otwórz nawias okrągły new FileReader otwórz nawias okrągły cudzysłów dane kropka txt cudzysłów zamknij nawias okrągły zamknij nawias okrągły średnik. Linia 12. String wiersz średnik. Linia 14. while otwórz nawias okrągły otwórz nawias okrągły wiersz znak równości plik kropka readLine otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły wykrzyknik znak równości null zamknij nawias okrągły otwórz nawias klamrowy. Linia 15. dane kropka add otwórz nawias okrągły Arrays kropka stream otwórz nawias okrągły wiersz kropka split otwórz nawias okrągły cudzysłów cudzysłów zamknij nawias okrągły zamknij nawias okrągły kropka map otwórz nawias okrągły Integer dwukropek dwukropek parseInt zamknij nawias okrągły kropka collect otwórz nawias okrągły Collectors kropka toList otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły zamknij nawias okrągły średnik. Linia 16. zamknij nawias klamrowy. Linia 17. plik kropka close otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 19. prawy ukośnik prawy ukośnik wypisanie odczytanych danych. Linia 20. for otwórz nawias okrągły List ampersant lt średnik Integer ampersant gt średnik liczby dwukropek dane zamknij nawias okrągły otwórz nawias klamrowy. Linia 21. for otwórz nawias okrągły Integer liczba dwukropek liczby zamknij nawias okrągły. Linia 22. System kropka out kropka print otwórz nawias okrągły liczba plus cudzysłów cudzysłów zamknij nawias okrągły średnik. Linia 23. System kropka out kropka println otwórz nawias okrągły cudzysłów cudzysłów zamknij nawias okrągły średnik. Linia 24. zamknij nawias klamrowy. Linia 25. zamknij nawias klamrowy otwórz nawias ostrokątny prawy ukośnik code zamknij nawias ostrokątny. Linia 27. zamknij nawias klamrowy.

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

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:

Linia 1. BufferedReader plik znak równości new BufferedReader otwórz nawias okrągły new InputStreamReader otwórz nawias okrągły System kropka in zamknij nawias okrągły zamknij nawias okrągły.
Linia 1. import java kropka io kropka BufferedReader średnik. Linia 2. import java kropka io kropka InputStreamReader średnik. Linia 3. import java kropka io kropka IOException średnik. Linia 4. import java kropka util kropka asterysk średnik. Linia 5. import java kropka util kropka stream kropka Collectors średnik. Linia 7. public class Main otwórz nawias klamrowy. Linia 8. otwórz nawias ostrokątny code style znak równości cudzysłów white minus space dwukropek pre średnik cudzysłów data minus inline zamknij nawias ostrokątny public static void main otwórz nawias okrągły String otwórz nawias kwadratowy zamknij nawias kwadratowy args zamknij nawias okrągły throws IOException otwórz nawias klamrowy. Linia 9. prawy ukośnik prawy ukośnik Lista list. Linia 10. List ampersant lt średnik List ampersant lt średnik Integer ampersant gt średnik ampersant gt średnik dane znak równości new ArrayList ampersant lt średnik ampersant gt średnik otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 11. BufferedReader plik znak równości new BufferedReader otwórz nawias okrągły new InputStreamReader otwórz nawias okrągły System kropka in zamknij nawias okrągły zamknij nawias okrągły średnik. Linia 12. String wiersz średnik. Linia 14. while otwórz nawias okrągły otwórz nawias okrągły wiersz znak równości plik kropka readLine otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły wykrzyknik znak równości null zamknij nawias okrągły otwórz nawias klamrowy. Linia 15. dane kropka add otwórz nawias okrągły Arrays kropka stream otwórz nawias okrągły wiersz kropka split otwórz nawias okrągły cudzysłów cudzysłów zamknij nawias okrągły zamknij nawias okrągły kropka map otwórz nawias okrągły Integer dwukropek dwukropek parseInt zamknij nawias okrągły kropka collect otwórz nawias okrągły Collectors kropka toList otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły zamknij nawias okrągły średnik. Linia 16. zamknij nawias klamrowy. Linia 17. plik kropka close otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 19. prawy ukośnik prawy ukośnik wypisanie odczytanych liczb. Linia 20. for otwórz nawias okrągły List ampersant lt średnik Integer ampersant gt średnik liczby dwukropek dane zamknij nawias okrągły otwórz nawias klamrowy. Linia 21. for otwórz nawias okrągły Integer liczba dwukropek liczby zamknij nawias okrągły. Linia 22. System kropka out kropka print otwórz nawias okrągły liczba plus cudzysłów cudzysłów zamknij nawias okrągły średnik. Linia 23. System kropka out kropka println otwórz nawias okrągły cudzysłów cudzysłów zamknij nawias okrągły średnik. Linia 24. zamknij nawias klamrowy. Linia 25. zamknij nawias klamrowy otwórz nawias ostrokątny prawy ukośnik code zamknij nawias ostrokątny. Linia 27. zamknij nawias klamrowy.

Polecenia niezbędne do przetestowania powyższej wersji wydajemy w terminalu:

Linia 1. javac plikZKodem kropka java. Linia 2. java plikZKodem otwórz nawias ostrokątny dane kropka txt zamknij nawias ostrokątny wyniki kropka txt.

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().

Słownik

inkrementacja
inkrementacja

zwiększenie danej wartości o jeden

oś symetrii
oś symetrii

prosta, względem której dane dwie figury są symetryczne

piksel
piksel

(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)