{"id":"informatyka-2019-maj-matura-rozszerzona/zad/6.2","paper_id":"informatyka-2019-maj-matura-rozszerzona","number":"6.2","points":3,"ptype":"open","subject":"informatyka","category":"matura","year":2019,"month":"maj","level":"rozszerzona","text":"Kontekst - patrz zadanie 6.1.\n\nPodaj listę różnych rodzin zapachów. Dla każdej rodziny podaj jej nazwę, cenę najtańszych perfum z tej rodziny i ich nazwę.","answer":null,"answer_text":null,"solution":"## Poprawna odpowiedź\n\n**18 rodzin zapachów z najtańszymi perfumami:**\n\n| Rodzina zapachów | Cena | Nazwa |\n| aromatyczna | 124 | Ibrary Ollec D'amore |\n| cytrusowa | 259 | Sian Grad |\n| cytrusowo-aromatyczna | 178 | Re Nostrum,ir |\n| drzewna | 123 | Pperlee Bouquet |\n| kwiatowa | 110 | Ose Deurmaline |\n| kwiatowo-drzewna | 104 | Rougna |\n| kwiatowo-orientalna | 103 | Arla : Vivace |\n| kwiatowo-szyprowa | 287 | Etish Pothal |\n| orientalna | 113 | Anille La Tosca |\n| orientalna lagodna | 122 | Ndy Warhol S Rose |\n| orientalno-drzewna | 138 | LackNight |\n| owocowa | 154 | Ake Perfucturne |\n| pudrowa | 139 | Ivm Cristal |\n| skorzana | 112 | Ui Mare |\n| szyprowa | 226 | Usk ti 1888 |\n| szyprowo-skorzana | 158 | Uir OtPlace |\n| wodna | 146 | Ilver Mounaya |\n| zielona | 406 | EOman |\n\n## Sposób 1 - SQL z podzapytaniem (najtańsze per rodzina)\n\n```sql\nSELECT p.rodzina_zapachow, p.cena, p.nazwa_p\nFROM perfumy p\nINNER JOIN (\nSELECT rodzina_zapachow, MIN(cena) AS min_cena\nFROM perfumy\nGROUP BY rodzina_zapachow\n) m ON p.rodzina_zapachow = m.rodzina_zapachow AND p.cena = m.min_cena\nORDER BY p.rodzina_zapachow;\n\n**Wyjaśnienie:** Podzapytanie znajduje najniższą cenę per rodzina. JOIN z tabelą perfumy daje też nazwę produktu o tej cenie.\n\n## Sposób 2 - Python z agregacją\n\n```python\nfrom collections import defaultdict\n\nnajtansze = {} # rodzina -> (cena, nazwa)\n\nwith open('perfumy.txt', encoding='utf-8') as f:\nf.readline()\nfor linia in f:\npola = linia.strip().split('\\t')\nid_p, nazwa, id_m, rodzina, cena = pola\ncena = int(cena)\nif rodzina not in najtansze or cena < najtansze[rodzina][0]:\nnajtansze[rodzina] = (cena, nazwa)\n\nfor rodzina in sorted(najtansze):\ncena, nazwa = najtansze[rodzina]\nprint(f'{rodzina:30} {cena:5} {nazwa}')\n\n## Sposób 3 - arkusz kalkulacyjny (tabela przestawna)\n\n**Wariant 1 (tabela przestawna):**\n1. Wstaw → Tabela przestawna.\n2. Wiersze: `rodzina_zapachow`.\n3. Wartości: `cena` z funkcją MIN.\n\nTo daje rodzinę + minimalną cenę. Aby uzyskać nazwę produktu - INDEX/MATCH:\n\n=INDEKS(perfumy!B:B; PODAJ.POZYCJĘ(1; (perfumy!D:D=A2)*(perfumy!E:E=B2); 0))\n(formuła tablicowa, Ctrl+Shift+Enter)\n\n## Reference informatyczny - GROUP BY z dodatkowymi kolumnami\n\n> Reference - Typowy problem \"min/max group_by z innym polem\":\n> - SQL standard: GROUP BY zwraca tylko grupę + agregat. Aby dodać inną kolumnę (np. nazwa_p), potrzebujemy podzapytania lub window function.\n> - Podzapytanie: `JOIN (SELECT rodzina, MIN(cena) FROM perfumy GROUP BY rodzina) ON `.\n> - Window function (nowoczesny SQL): `ROW_NUMBER() OVER (PARTITION BY rodzina ORDER BY cena ASC) = 1`.\n> - Python defaultdict z iteracyjnym update - najwygodniej.\n\n## Schemat oceniania CKE\n\n> Klucz CKE (zadanie 6.2, max 3 pkt):\n> - **1 pkt** - prawidłowa lista 18 rodzin zapachów\n> - **1 pkt** - cena najtańszych perfum dla każdej rodziny\n> - **1 pkt** - nazwa najtańszych perfum dla każdej rodziny\n> - **0 pkt** - błędna lub brak\n\n## Typowe pułapki\n\n- **`SELECT rodzina, MIN(cena), nazwa_p`** - bez podzapytania! W standardowym SQL to BŁĄD (nazwa_p nie jest w GROUP BY i nie jest agregatem).\n- **Brak DISTINCT** - duplikaty rodzin jeśli ta sama rodzina ma kilka perfum o tej samej minimalnej cenie.\n- **Sortowanie** - nie jest wymagane przez treść, ale ułatwia czytanie.\n- **Pomylenie kolumn** - w perfumy.txt: id_perfum, nazwa_p, id_marki, rodzina_zapachow, cena.\n\n## Złożoność obliczeniowa\n\n- SQL z indeksem na rodzina_zapachow: O(n log n) sortowanie + O(n) join.\n- Python defaultdict: O(n) - n = liczba perfum.\n- Wynik: 18 rodzin (z danych).","image":null,"solution_image":null,"topics":null,"page_from":null,"source":"maturazai","answer_source":null,"answer_text_source":null,"solution_source":"maturazai","text_source":"maturazai","source_label":"Informatyka · Matura · maj 2019 (rozszerzona)","subject_label":"Informatyka","category_label":"Matura","text_html":"<p>Kontekst - patrz zadanie 6.1.</p>\n<p>Podaj listę różnych rodzin zapachów. Dla każdej rodziny podaj jej nazwę, cenę najtańszych perfum z tej rodziny i ich nazwę.</p>","solutions":[{"source":"maturazai","label":"maturazai.pl (AI)","kind":"text","html":"<h4>Poprawna odpowiedź</h4>\n<p><strong>18 rodzin zapachów z najtańszymi perfumami:</strong></p>\n<p>| Rodzina zapachów | Cena | Nazwa |<br>| aromatyczna | 124 | Ibrary Ollec D&#x27;amore |<br>| cytrusowa | 259 | Sian Grad |<br>| cytrusowo-aromatyczna | 178 | Re Nostrum,ir |<br>| drzewna | 123 | Pperlee Bouquet |<br>| kwiatowa | 110 | Ose Deurmaline |<br>| kwiatowo-drzewna | 104 | Rougna |<br>| kwiatowo-orientalna | 103 | Arla : Vivace |<br>| kwiatowo-szyprowa | 287 | Etish Pothal |<br>| orientalna | 113 | Anille La Tosca |<br>| orientalna lagodna | 122 | Ndy Warhol S Rose |<br>| orientalno-drzewna | 138 | LackNight |<br>| owocowa | 154 | Ake Perfucturne |<br>| pudrowa | 139 | Ivm Cristal |<br>| skorzana | 112 | Ui Mare |<br>| szyprowa | 226 | Usk ti 1888 |<br>| szyprowo-skorzana | 158 | Uir OtPlace |<br>| wodna | 146 | Ilver Mounaya |<br>| zielona | 406 | EOman |</p>\n<h4>Sposób 1 - SQL z podzapytaniem (najtańsze per rodzina)</h4>\n<p>```sql<br>SELECT p.rodzina_zapachow, p.cena, p.nazwa_p<br>FROM perfumy p<br>INNER JOIN (<br>SELECT rodzina_zapachow, MIN(cena) AS min_cena<br>FROM perfumy<br>GROUP BY rodzina_zapachow<br>) m ON p.rodzina_zapachow = m.rodzina_zapachow AND p.cena = m.min_cena<br>ORDER BY p.rodzina_zapachow;</p>\n<p><strong>Wyjaśnienie:</strong> Podzapytanie znajduje najniższą cenę per rodzina. JOIN z tabelą perfumy daje też nazwę produktu o tej cenie.</p>\n<h4>Sposób 2 - Python z agregacją</h4>\n<p>```python<br>from collections import defaultdict</p>\n<p>najtansze = {} # rodzina -&gt; (cena, nazwa)</p>\n<p>with open(&#x27;perfumy.txt&#x27;, encoding=&#x27;utf-8&#x27;) as f:<br>f.readline()<br>for linia in f:<br>pola = linia.strip().split(&#x27;\\t&#x27;)<br>id_p, nazwa, id_m, rodzina, cena = pola<br>cena = int(cena)<br>if rodzina not in najtansze or cena &lt; najtansze[rodzina][0]:<br>najtansze[rodzina] = (cena, nazwa)</p>\n<p>for rodzina in sorted(najtansze):<br>cena, nazwa = najtansze[rodzina]<br>print(f&#x27;{rodzina:30} {cena:5} {nazwa}&#x27;)</p>\n<h4>Sposób 3 - arkusz kalkulacyjny (tabela przestawna)</h4>\n<p><strong>Wariant 1 (tabela przestawna):</strong></p>\n<ol><li>Wstaw → Tabela przestawna.</li><li>Wiersze: <code>rodzina_zapachow</code>.</li><li>Wartości: <code>cena</code> z funkcją MIN.</li></ol>\n<p>To daje rodzinę + minimalną cenę. Aby uzyskać nazwę produktu - INDEX/MATCH:</p>\n<p>=INDEKS(perfumy!B:B; PODAJ.POZYCJĘ(1; (perfumy!D:D=A2)*(perfumy!E:E=B2); 0))<br>(formuła tablicowa, Ctrl+Shift+Enter)</p>\n<h4>Reference informatyczny - GROUP BY z dodatkowymi kolumnami</h4>\n<blockquote>Reference - Typowy problem &quot;min/max group_by z innym polem&quot;:<br>- SQL standard: GROUP BY zwraca tylko grupę + agregat. Aby dodać inną kolumnę (np. nazwa_p), potrzebujemy podzapytania lub window function.<br>- Podzapytanie: <code>JOIN (SELECT rodzina, MIN(cena) FROM perfumy GROUP BY rodzina) ON </code>.<br>- Window function (nowoczesny SQL): <code>ROW_NUMBER() OVER (PARTITION BY rodzina ORDER BY cena ASC) = 1</code>.<br>- Python defaultdict z iteracyjnym update - najwygodniej.</blockquote>\n<h4>Schemat oceniania CKE</h4>\n<blockquote>Klucz CKE (zadanie 6.2, max 3 pkt):<br>- <strong>1 pkt</strong> - prawidłowa lista 18 rodzin zapachów<br>- <strong>1 pkt</strong> - cena najtańszych perfum dla każdej rodziny<br>- <strong>1 pkt</strong> - nazwa najtańszych perfum dla każdej rodziny<br>- <strong>0 pkt</strong> - błędna lub brak</blockquote>\n<h4>Typowe pułapki</h4>\n<ul><li><strong><code>SELECT rodzina, MIN(cena), nazwa_p</code></strong> - bez podzapytania! W standardowym SQL to BŁĄD (nazwa_p nie jest w GROUP BY i nie jest agregatem).</li><li><strong>Brak DISTINCT</strong> - duplikaty rodzin jeśli ta sama rodzina ma kilka perfum o tej samej minimalnej cenie.</li><li><strong>Sortowanie</strong> - nie jest wymagane przez treść, ale ułatwia czytanie.</li><li><strong>Pomylenie kolumn</strong> - w perfumy.txt: id_perfum, nazwa_p, id_marki, rodzina_zapachow, cena.</li></ul>\n<h4>Złożoność obliczeniowa</h4>\n<ul><li>SQL z indeksem na rodzina_zapachow: O(n log n) sortowanie + O(n) join.</li><li>Python defaultdict: O(n) - n = liczba perfum.</li><li>Wynik: 18 rodzin (z danych).</li></ul>"}]}