{"id":"informatyka-2019-maj-matura-rozszerzona/zad/6.5","paper_id":"informatyka-2019-maj-matura-rozszerzona","number":"6.5","points":2,"ptype":"open","subject":"informatyka","category":"matura","year":2019,"month":"maj","level":"rozszerzona","text":"Kontekst - patrz zadanie 6.1.\n\nIstnieją marki, których wszystkie perfumy należą do tylko jednej rodziny zapachów. Podaj listę wszystkich nazw takich marek. Lista powinna zawierać nazwy marek i nazwy odpowiednich rodzin zapachów.","answer":null,"answer_text":null,"solution":"## Poprawna odpowiedź\n\n**Marki, których wszystkie perfumy należą do dokładnie jednej rodziny zapachów:**\n\n| Nazwa marki | Rodzina zapachów |\n| **Ightce** | aromatyczna |\n| **X ICologne** | orientalno-drzewna |\n| **Nnick a Kieffo** | orientalna |\n| **Enmith** | kwiatowo-orientalna |\n| **Issmkunstwerke** | orientalna |\n\nIstnieje 5 takich marek. Kluczowa interpretacja: marka może mieć WIELE perfum, ale wszystkie muszą mieć tę samą wartość `rodzina_zapachow`.\n\n## Sposób 1 - SQL (GROUP BY z HAVING COUNT DISTINCT = 1)\n\n```sql\nSELECT m.nazwa_m, MIN(p.rodzina_zapachow) AS rodzina\nFROM marki m\nINNER JOIN perfumy p ON m.id_marki = p.id_marki\nGROUP BY m.id_marki, m.nazwa_m\nHAVING COUNT(DISTINCT p.rodzina_zapachow) = 1;\n\n**Wyjaśnienie:**\n- Grupujemy perfumy po marce.\n- `COUNT(DISTINCT rodzina_zapachow) = 1` → marka ma tylko 1 unikalną rodzinę.\n- `MIN(rodzina_zapachow)` zwraca tę jedyną rodzinę (można też `MAX` - wynik ten sam, bo unikalna).\n\n**Wynik:**\nIghtce | aromatyczna\nX ICologne | orientalno-drzewna\nNnick a Kieffo | orientalna\nEnmith | kwiatowo-orientalna\nIssmkunstwerke | orientalna\n\n## Sposób 2 - Python (zbiory)\n\n```python\nfrom collections import defaultdict\n\n# Wczytaj marki: id -> nazwa\nmarki = {}\nwith open('marki.txt', encoding='utf-8') as f:\nf.readline() # naglowek\nfor linia in f:\nidm, nazwa = linia.strip().split('\\t')\nmarki[idm] = nazwa\n\n# Dla kazdej marki zbierz zbior rodzin\nrodziny_per_marka = defaultdict(set)\nwith open('perfumy.txt', encoding='utf-8') as f:\nf.readline()\nfor linia in f:\nidp, nazwa, idm, rodzina, cena = linia.strip().split('\\t')\nrodziny_per_marka[idm].add(rodzina)\n\n# Wybierz marki z dokladnie jedna rodzina\nfor idm, zbior in rodziny_per_marka.items():\nif len(zbior) == 1:\nrodzina = next(iter(zbior))\nprint(f'{marki[idm]:25} | {rodzina}')\n\n## Sposób 3 - arkusz kalkulacyjny (tabela przestawna)\n\n**Krok 1:** Wczytaj perfumy.txt. Dodaj kolumnę nazwa marki (WYSZUKAJ.PIONOWO po id_marki w marki.txt).\n\n**Krok 2:** Tabela przestawna:\n- Wiersze: `nazwa_m`\n- Wartości: `rodzina_zapachow` z funkcją LICZBA UNIKATOWYCH (lub LICZ.UNIKATOWE.WARTOŚCI).\n\n**Krok 3:** Filtruj wiersze, gdzie liczba unikalnych rodzin = 1.\n\n**Krok 4:** Dla pozostałych marek znajdź tę jedyną rodzinę: `=INDEKS( )` lub przez drugą tabelę przestawną.\n\n## Reference algorytmiczny - COUNT DISTINCT w HAVING\n\n> Reference - Filtr na zagregowanej unikalności:\n> - `COUNT(DISTINCT kol) = 1` → wszystkie wartości w grupie są identyczne.\n> - `HAVING` filtruje grupy PO agregacji (nie pojedyncze wiersze - to robi WHERE).\n> - W Pythonie: `len(set( )) == 1` lub porównanie pierwszej i ostatniej wartości po sortowaniu.\n> - **Zwracanie wartości grupowej:** `MIN(kol)` lub `MAX(kol)` dla unikalnej wartości - daje tę jedyną wartość.\n\n## Schemat oceniania CKE\n\n> Klucz CKE (zadanie 6.5, max 2 pkt):\n> - **2 pkt** - pełna prawidłowa odpowiedź: nazwy 5 marek i 5 odpowiednich rodzin zapachów.\n> - **1 pkt** - tylko prawidłowa lista 5 marek (bez rodzin).\n> - **1 pkt** - lista 3 lub 4 marek z 5 w parze z prawidłową nazwą rodziny zapachów.\n> - **0 pkt** - błędna lub brak.\n\n## Typowe pułapki\n\n- **`COUNT(rodzina_zapachow) = 1`** zamiast `COUNT(DISTINCT rodzina_zapachow) = 1` - to pierwsze daje marki z tylko JEDNYM perfumem (a my chcemy marki z wieloma perfumami, byle z tej samej rodziny).\n- **Pominięcie marki z 1 perfumem** - jeśli marka ma tylko 1 perfum, to oczywiście ma 1 rodzinę. Te marki też zaliczają się do wyniku.\n- **Brak JOIN z `marki`** - w perfumy.txt jest tylko id_marki, potrzebujemy nazwa_m.\n- **GROUP BY tylko po id_marki** - niektóre silniki SQL wymagają wszystkich kolumn z SELECT także w GROUP BY (poza agregatami). Dla pewności dodaj `m.nazwa_m` do GROUP BY.\n- **Pominięcie kolumny z rodziną** - utrata 1 pkt z 2.\n- **Marki nie mające w ogóle perfum** - INNER JOIN je odfiltruje, a to dobrze (marka bez perfum nie ma rodziny).\n\n## Złożoność obliczeniowa\n\n- SQL z GROUP BY + COUNT DISTINCT: O(N log N) dla sortowania per grupa.\n- Python z defaultdict set: O(N) jedno przejście + O(M) wybieranie marek.\n- **Całkowita: O(N + M)** liniowa.","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>Istnieją marki, których wszystkie perfumy należą do tylko jednej rodziny zapachów. Podaj listę wszystkich nazw takich marek. Lista powinna zawierać nazwy marek i nazwy odpowiednich rodzin zapachów.</p>","solutions":[{"source":"maturazai","label":"maturazai.pl (AI)","kind":"text","html":"<h4>Poprawna odpowiedź</h4>\n<p><strong>Marki, których wszystkie perfumy należą do dokładnie jednej rodziny zapachów:</strong></p>\n<p>| Nazwa marki | Rodzina zapachów |<br>| <strong>Ightce</strong> | aromatyczna |<br>| <strong>X ICologne</strong> | orientalno-drzewna |<br>| <strong>Nnick a Kieffo</strong> | orientalna |<br>| <strong>Enmith</strong> | kwiatowo-orientalna |<br>| <strong>Issmkunstwerke</strong> | orientalna |</p>\n<p>Istnieje 5 takich marek. Kluczowa interpretacja: marka może mieć WIELE perfum, ale wszystkie muszą mieć tę samą wartość <code>rodzina_zapachow</code>.</p>\n<h4>Sposób 1 - SQL (GROUP BY z HAVING COUNT DISTINCT = 1)</h4>\n<p>```sql<br>SELECT m.nazwa_m, MIN(p.rodzina_zapachow) AS rodzina<br>FROM marki m<br>INNER JOIN perfumy p ON m.id_marki = p.id_marki<br>GROUP BY m.id_marki, m.nazwa_m<br>HAVING COUNT(DISTINCT p.rodzina_zapachow) = 1;</p>\n<p><strong>Wyjaśnienie:</strong></p>\n<ul><li>Grupujemy perfumy po marce.</li><li><code>COUNT(DISTINCT rodzina_zapachow) = 1</code> → marka ma tylko 1 unikalną rodzinę.</li><li><code>MIN(rodzina_zapachow)</code> zwraca tę jedyną rodzinę (można też <code>MAX</code> - wynik ten sam, bo unikalna).</li></ul>\n<p><strong>Wynik:</strong><br>Ightce | aromatyczna<br>X ICologne | orientalno-drzewna<br>Nnick a Kieffo | orientalna<br>Enmith | kwiatowo-orientalna<br>Issmkunstwerke | orientalna</p>\n<h4>Sposób 2 - Python (zbiory)</h4>\n<p>```python<br>from collections import defaultdict</p>\n<h3>Wczytaj marki: id -&gt; nazwa</h3>\n<p>marki = {}<br>with open(&#x27;marki.txt&#x27;, encoding=&#x27;utf-8&#x27;) as f:<br>f.readline() # naglowek<br>for linia in f:<br>idm, nazwa = linia.strip().split(&#x27;\\t&#x27;)<br>marki[idm] = nazwa</p>\n<h3>Dla kazdej marki zbierz zbior rodzin</h3>\n<p>rodziny_per_marka = defaultdict(set)<br>with open(&#x27;perfumy.txt&#x27;, encoding=&#x27;utf-8&#x27;) as f:<br>f.readline()<br>for linia in f:<br>idp, nazwa, idm, rodzina, cena = linia.strip().split(&#x27;\\t&#x27;)<br>rodziny_per_marka[idm].add(rodzina)</p>\n<h3>Wybierz marki z dokladnie jedna rodzina</h3>\n<p>for idm, zbior in rodziny_per_marka.items():<br>if len(zbior) == 1:<br>rodzina = next(iter(zbior))<br>print(f&#x27;{marki[idm]:25} | {rodzina}&#x27;)</p>\n<h4>Sposób 3 - arkusz kalkulacyjny (tabela przestawna)</h4>\n<p><strong>Krok 1:</strong> Wczytaj perfumy.txt. Dodaj kolumnę nazwa marki (WYSZUKAJ.PIONOWO po id_marki w marki.txt).</p>\n<p><strong>Krok 2:</strong> Tabela przestawna:</p>\n<ul><li>Wiersze: <code>nazwa_m</code></li><li>Wartości: <code>rodzina_zapachow</code> z funkcją LICZBA UNIKATOWYCH (lub LICZ.UNIKATOWE.WARTOŚCI).</li></ul>\n<p><strong>Krok 3:</strong> Filtruj wiersze, gdzie liczba unikalnych rodzin = 1.</p>\n<p><strong>Krok 4:</strong> Dla pozostałych marek znajdź tę jedyną rodzinę: <code>=INDEKS( )</code> lub przez drugą tabelę przestawną.</p>\n<h4>Reference algorytmiczny - COUNT DISTINCT w HAVING</h4>\n<blockquote>Reference - Filtr na zagregowanej unikalności:<br>- <code>COUNT(DISTINCT kol) = 1</code> → wszystkie wartości w grupie są identyczne.<br>- <code>HAVING</code> filtruje grupy PO agregacji (nie pojedyncze wiersze - to robi WHERE).<br>- W Pythonie: <code>len(set( )) == 1</code> lub porównanie pierwszej i ostatniej wartości po sortowaniu.<br>- <strong>Zwracanie wartości grupowej:</strong> <code>MIN(kol)</code> lub <code>MAX(kol)</code> dla unikalnej wartości - daje tę jedyną wartość.</blockquote>\n<h4>Schemat oceniania CKE</h4>\n<blockquote>Klucz CKE (zadanie 6.5, max 2 pkt):<br>- <strong>2 pkt</strong> - pełna prawidłowa odpowiedź: nazwy 5 marek i 5 odpowiednich rodzin zapachów.<br>- <strong>1 pkt</strong> - tylko prawidłowa lista 5 marek (bez rodzin).<br>- <strong>1 pkt</strong> - lista 3 lub 4 marek z 5 w parze z prawidłową nazwą rodziny zapachów.<br>- <strong>0 pkt</strong> - błędna lub brak.</blockquote>\n<h4>Typowe pułapki</h4>\n<ul><li><strong><code>COUNT(rodzina_zapachow) = 1</code></strong> zamiast <code>COUNT(DISTINCT rodzina_zapachow) = 1</code> - to pierwsze daje marki z tylko JEDNYM perfumem (a my chcemy marki z wieloma perfumami, byle z tej samej rodziny).</li><li><strong>Pominięcie marki z 1 perfumem</strong> - jeśli marka ma tylko 1 perfum, to oczywiście ma 1 rodzinę. Te marki też zaliczają się do wyniku.</li><li><strong>Brak JOIN z <code>marki</code></strong> - w perfumy.txt jest tylko id_marki, potrzebujemy nazwa_m.</li><li><strong>GROUP BY tylko po id_marki</strong> - niektóre silniki SQL wymagają wszystkich kolumn z SELECT także w GROUP BY (poza agregatami). Dla pewności dodaj <code>m.nazwa_m</code> do GROUP BY.</li><li><strong>Pominięcie kolumny z rodziną</strong> - utrata 1 pkt z 2.</li><li><strong>Marki nie mające w ogóle perfum</strong> - INNER JOIN je odfiltruje, a to dobrze (marka bez perfum nie ma rodziny).</li></ul>\n<h4>Złożoność obliczeniowa</h4>\n<ul><li>SQL z GROUP BY + COUNT DISTINCT: O(N log N) dla sortowania per grupa.</li><li>Python z defaultdict set: O(N) jedno przejście + O(M) wybieranie marek.</li><li><strong>Całkowita: O(N + M)</strong> liniowa.</li></ul>"}]}