PO: Informatica Olympiade

Vergelijkbare documenten
PO: Informatica Olympiade

PO: Informatica Olympiade

De eerste ronde Nederlandse Informatica Olympiade

PO: Informatica Olympiade

De eerste ronde Nederlandse Informatica Olympiade

Je gaat leren programmeren en een spel bouwen met de programmeertaal Python. Websites zoals YouTube en Instagram zijn gebouwd met Python.

DomJudge-Practicum. Open Dag UU

Programmeermethoden. Recursie. week 11: november kosterswa/pm/

Algemeen. Rorschachtest. Algemene info

Practicumopgave 3: SAT-solver

De eerste ronde Nederlandse Informatica Olympiade

Simon de schildpad J van Weert 1

Simon de schildpad J van Weert 1

Uitleg: In de bovenstaande oefening zie je in het eerste blokje een LEES en een SCHRIJF opdracht. Dit is nog lesstof uit het tweede trimester.

Een spoedcursus python

Je gaat leren programmeren in Ruby. En daarna in Ruby een spelletje maken. Websites zoals Twitch en Twitter gemaakt zijn met behulp van Ruby?

Stroomschema s maken op papier

Small Basic Programmeren Text Console 2

DE ASTRO PI PROGRAMMEREN VOOR MISSION ZERO

Stroomschema s maken in Word

OEFENINGEN PYTHON REEKS 6

Programmeermethoden. Recursie. Walter Kosters. week 11: november kosterswa/pm/

BEGINNER JAVA Inhoudsopgave

Opgave 2. Binaire informatie

Inleiding Programmeren 2

Uitwerking tentamen Algoritmiek 10 juni :00 13:00

Kennismaking met programmeren

Meer Blokken. 1. Dit is een functie genaamd Maximum, die twee argumenten heeft: number1 en number2.

[13] Rondjes draaien (loops)

Zo gaat jouw kunstwerk er straks uitzien. Of misschien wel heel anders.

extra oefening algoritmiek - antwoorden

Inhoudsopgave Voorwoord 5 Voordat je begint 6 Wat heb je nodig? 7 De website bij het boek 7 Voor ouders, verzorgers en leraren

Toetsvoorbereiding Informatica HAVO/VWO 5 (T51) Programmeren met Python II. Duur: 70 minuten Datum: sept 2018

Programmeeropdracht 2 Toernooi Algoritmiek, voorjaar 2019

Minder bekende functies in Excel

Programmeermethoden NA. Week 5: Functies (vervolg)

Programmeermethoden NA

Controle structuren. Keuze. Herhaling. Het if statement. even1.c : testen of getal even of oneven is. statement1 statement2

P O P Y T H O N P R O G R AMMER EN: G A N Z E N B O R D

Inleiding Programmeren 2

PYTHON REEKS 1: BASICS. Mathias Polfliet

Disclaimer Het bestand dat voor u ligt, is nog in ontwikkeling. Op verzoek is deze versie digitaal gedeeld. Wij willen de lezer er dan ook op wijzen

Scratch. Gemaakt door: Déjan van Noordt en Leroy van den Driesche Leerlingen HAVO 5 SG Spieringshoek Als onderdeel voor het vak Informatica

Informatica: C# WPO 10

Inhoudsopgave Voorwoord 5 Nieuwsbrief 5 Introductie Visual Steps 6 Wat heeft u nodig? 6 Voorkennis 7 Hoe werkt u met dit boek?

De eerste ronde Nederlandse Informatica Olympiade

Programmeermethoden NA. Week 6: Lijsten

Vierde college algoritmiek. 2 maart Toestand-actie-ruimte Exhaustive Search

Programmeermethoden NA. Week 5: Functies (vervolg)

Seven segments of Pi

Variabelen en statements in ActionScript

Inleiding Programmeren 2

Handleiding bij de Booktest Generator

3. Structuren in de taal

Divide & Conquer: Verdeel en Heers vervolg. Algoritmiek

7. Je bericht in Nieuws & acties aanpassen

GO spelregels. Wim Berkelmans

Combinatoriek groep 1 & 2: Recursie

5e inlever opdracht Excel: ICT cijferlijst. Stap 1: De eerste inhoud. Stap 2: Een beetje opmaak

Uitwerking tentamen Analyse van Algoritmen, 29 januari

Klonen. Het doel is om de appel op te eten. Iedere keer dat de slang de appel eet, groeit hij één vakje langer.

Programmeermethoden NA. Week 3: Controlestructuren

Dit instructieboek is een kopie van het echte NK. Alleen de puzzels zijn verwijderd.

De jury beslist of een inzending geldig is. Over de uitslag kan niet worden gecorrespondeerd. WCPN Nederlands Kampioenschap 2014

Je kent natuurlijk Mondriaan wel. Teken eerst eens een mooie Mondriaan.

Recursion. Introductie 37. Leerkern 37. Terugkoppeling 40. Uitwerking van de opgaven 40

Programmeren in C++ Efficiënte zoekfunctie in een boek

HANDLEIDING PROGRAMMEREN IN PASCAL (LAZARUS)

Wooncomplexinformatie op woonzorg.nl

ALGORITMIEK: antwoorden werkcollege 5

ALGORITMIEK: antwoorden werkcollege 5

Labo 2 Programmeren II

Excel opdracht: ICT cijferlijst. Stap 1: De eerste inhoud. Stap 2: Een beetje opmaak

Scratch Rekenen & programmeren

De Sense HAT programmeren Je eerste computerprogramma

Gebruikersinstructie Spam- & Virusfilter QNS Quality Network Services

Programmeerstructuren met App Inventor

Functioneel programmeren

Rekentijger - Groep 7 Tips bij werkboekje A

Stroomschema s maken op papier

[15] Variabelen in functies (of: een woordje over scope)

5. Geavanceerde formules

leerlingbrochure nld Door: Jolanthe Jansen


Scratch les 1 Rekenen

Grafieken jaar. Rekenles over het maken van grafieken. Rekenen. 60 minuten. Weerstation, data, grafieken

Dinsdag 10 juni uur

Wat is itslearning..?

recursie Hoofdstuk 5 Studeeraanwijzingen De studielast van deze leereenheid bedraagt circa 6 uur. Terminologie

Scratch in drie uur. Hallo, mijn naam is Minti Mint! Ik ga je uitleggen hoe je je eigen computerspel kunt maken. We gaan een racespel maken!

Hoofdstuk 20: Wiskundige functies

Informatica: C# WPO 11

Zevende college algoritmiek. 24 maart Verdeel en Heers

Tentamen Imperatief en Object-georiënteerd programmeren in Java voor CKI

Excel reader. Beginner Gemiddeld.

Transcriptie:

PO: Informatica Olympiade 2016-2017 Wat is de Informatica Olympiade? De Nederlandse Informatica Olympiade (NIO) is een programmeerwedstrijd voor de bovenbouw van het Voortgezet onderwijs. Het is een onderdeel van de International Olympiad in Informatics (IOI). De eerste ronde van de NIO bestaat uit 4 onderdelen A, B, C en D: Klik hier voor de officiële opgaven en een korte toelichting van de NIO. De 100 inzendingen met de meeste punten (mits deze minimaal 200 punten hebben gehaald) worden uitgenodigd voor de tweede ronde van de NIO in maart 2015 op de Technische Universiteit Twente. Om mee te doen aan de olympiade, moeten je uitwerkingen digitaal zijn ingeleverd bij de NIO voor 25 januari 2017. (Ze worden direct automatisch nagekeken en je kunt zo vaak nieuwe/verbeterde versies insturen als je wilt). De beste deelnemers van de tweede ronde gaan door naar de derde ronde om te bepalen wie er namens Nederland mee mag doen aan de Internationale Informatica Olympiade 2017 in Iran. 1

Inhoud Wat is de Informatica Olympiade?... 1 De PO... 3 Puntenverdeling:... 3 Inleveren en beoordeling:... 4 Automatisch nakijken... 4 Tips en tricks bij de A opgaven... 7 Opdracht 1: Vierkant (1,5 pnt)... 7 Opdracht 2: Klnkrwg (0,5 pnt)... 7 Opdracht 3: Collatz (1,5 pnt)... 7 Opdracht 4: Vullen (1,5 pnt):... 8 Opdracht 4: Brute force strategie... 9 Opdracht 4: Recursieve strategie... 13 Opdracht 5: Boomcentrum (1 pnt)... 14 Introductie recursie... 14 De opgave... 15 2

De PO Als PO voor Informatica gaan we de een deel van de opgaven van de eerste ronde van de NIO maken, namelijk die van categorie A en C. Je bent zelf vrij om ook daadwerkelijk mee te doen aan de Olympiade met je uitwerkingen (Met het maken van de PO ben je al een flink eind op weg, je kunt dan zelf de overige opgaven nog maken voor meer punten). Meer details over hoe je meedoet en welke voorwaarden er zijn, vind je in het document van de NIO op de informaticasite (en op www.informaticaolympiade.nl). Wt helpt je natuurlijk graag als je officieel mee wilt doen. De olympiade schrijft niet voor in welke programmeertaal je de oplossingen maakt. De opgaven zijn zo gemaakt dat je in principe in elke taal een oplossing kunt schrijven. In dit document ga ik er van uit dat je het in Python doet. Als je liever een andere taal gebruikt, mag dat natuurlijk ook. Puntenverdeling: Je doet deze PO alleen of met zijn tweeën. ( Let op: De deelname aan de NIO zelf is individueel, dus van een duo kan maar 1 persoon deelnemen, omdat je niet 2x dezelfde code in kunt/mag leveren. Als je toch allebei wilt deelnemen, zul je verschillende versies van je oplossingen moeten maken.) We maken voor de PO alleen opgaven A en C (en eventueel D als je wilt). Opgaven B worden uniek gegenereerd voor elke deelnemer. Zeker doen als je aan de Olympiade mee wilt doen, maar voor de PO slaan we ze over. De beoordeling van de PO is als volgt: - 1 punt cadeau - Je verslag en logboek leveren samen 1 punt op - Met het maken van opgaven A1 t/m A4 kun je 5 punten verdienen: o A1: 1,5 punt o A2: 0,5 punt o A3: 1,5 punt o A4: 1,5 punt - Met het maken van A5, en opgave C (en eventueel D als superbonus), zijn de laatste 3 punten te verdienen: o A5: 1,0 punt o C1: 0,5 punt o C2: 0,5 punt o C3: 0,5 punt o C4: 0,5 punt Deels correcte oplossingen van een opgave leveren een deel van de punten op, dus ook al kom je er niet uit, lever je beste poging van elke opgave toch in. Let op: de opgaven lopen op in moeilijkheid, maar de puntenwaardering ligt relatief zwaar op de eerste opgaven. Zo moet het voor iedereen mogelijk zijn een nette voldoende te halen en voor de doorzetters zijn hogere punten haalbaar. 3

Inleveren en beoordeling: Je levert bij Wt je gemaakte programma s in. Daarnaast maak je een begeleidend verslagje waarin je de code uitlegt. Hiermee help je mij jouw/jullie code te begrijpen en laat je zien dat je begrijpt wat je gedaan hebt (plagiaatcontrole). Tevens lever je een logboekje in met de bestede tijd per persoon. Dit geeft mij inzicht in jullie tijdsbesteding en kan dienen als bewijsmateriaal bij eventuele onenigheid binnen een duo. Let op: Omdat deze PO plagiaat gevoelig is (Wt heeft er eerder problemen mee gehad), let ik extra op het kopiëren van andermans code en op de codetoelichting die je in je verslag geeft. Bij twijfel zal Wt om een mondelinge toelichting vragen om te checken of je je eigen code hebt geschreven en snapt wat je hebt gedaan! Elkaar een beetje helpen mag natuurlijk, maar code inleveren die je zelf niet helemaal begrijpt en dus niet kan toelichten, mag niet. Je levert alle onderdelen van de PO (de programma s en het verslag) in in een.zip file bij de opdracht die openstaat in Magister. Je hoeft per groepje uiteraard maar 1 keer in te leveren. Uiterlijke inleverdatum: Donderdag 22 december om 23:59 uur Automatisch nakijken De informatica olympiade werkt met een automatisch nakijksysteem. Hierbij kun je een script dat je geschreven hebt als oplossing voor een van de opgaven inleveren. Er worden dan een aantal testcases automatisch op losgelaten en je krijgt punten voor elke testcase waarvoor je script het juiste antwoord geeft. Voor de testcases die misgaan krijg je te zien wat de foutmelding was (bv. Een fout antwoord, een error bij het runnen, maximale runtime overschreden, etc.). Met deze info kun je je scrpit eventueel verbeteren en weer een nieuwe versie indienen. Je kunt elke opgave zo vaak proberen als je wilt, de hoogste score blijft staan. Zelfs als je niet aan de officiële olympiade wilt meedoen kun je hier dankbaar gebruik van maken om je PO opgaven te testen. Het werkt als volgt: Ga naar http://submit.informaticaolympiade.nl/ en maak een account aan. Als je bent ingelogd zie je links alle A, B en C opgaven staan (en 00 is een testopgave voor als je wilt checken of het inleveren werkt). Klik op de opgave je je wilt inleveren en klik Voeg inzending toe. Je kunt nu een script uploaden. Vergeet niet de juiste programmeertaal te selecteren (Python 2): 4

Als je op opslaan klikt wordt je script geupload en uitgevoerd. Je ziet dan je inzending in de lijst staan met de status uitvoeren. Dit betekent dat je script op dit moment uitgeveord wordt. Als je na een paar seconden de pagina ververst (F5), dan zie je als het goed is de status op klaar staan en is er een score gegeven (max 40 voor elke A opgave): Je kunt nu op de inzending klikken voor meer info en eventuele foutmeldingen als je niet alle 40 punten hebt gehaald: 5

Als er foutmeldingen staan in de rechtertabel kunnen die je helpen de fouten in je script op te sporen. De rest van dit document bevat tips, hints en uitleg om je te helpen de A opgaven te tackelen (deels work in progress ) 6

Tips en tricks bij de A opgaven Opdracht 1: Vierkant (1,5 pnt) In deze opdracht wordt om een getal N gevraagd met 0 < N < 41. Op basis van dit getal maak je een vierkant van sterretjes en streepjes. De truuk bij deze opgave is om te bepalen wat de relatie is tussen een aantal onderdelen (getallen) van het vierkant en de grootte van N: Hoeveel regels is de output ten opzichte van N? (Dat is makkelijk, het zijn gewoon N regels) Wat is de relatie tussen het aantal sterretje op de eerste en laatste regel en N (ook makkelijk) Hoeveel tussenregels (regels die uit sterretjes en streepjes bestaan) zijn er ten opzichte van N? Hoeveel sterretjes staan er vooraan en achteraan op een tussenregel? Hoeveel streepjes staan er op een tussenregel ten opzichte van N? Als je deze info scherp hebt, kun je een programma met een (for) loop schrijven dat deze getallen omzet in de juiste hoeveelheid sterretjes en streepjes. N = 1 is een speciaal geval die het beste met een if zelf kunt checken om er meteen de juiste uitvoer bij te geven (hiervoor hoef je niet te rekenen/loopen natuurlijk Hint: Vergeet niet dat je in Python strings kunt vermenigvuldigen. Dus "x" * 6 geeft "xxxxxx". Dat komt hier bijzonder goed van pas Opdracht 2: Klnkrwg (0,5 pnt) Deze opgave hebben we al eerder gedaan. (*kuch* Wt opgave 9b *kuch*). Om je te motiveren om deze opgave toch nog te maken (en zo aan te passen dat hij wordt geaccepteerd door de olympiadesoftware), krijg je toch 0,5 punt voor deze vraag. Opdracht 3: Collatz (1,5 pnt) De olympiade heeft niet veel fantasie dit jaar... Deze opgave hebben we ook al eerder gemaakt in een net iets andere vorm. (*kuch* Wt opgave 12 *kuch*). Gelukkig moet je nog iets extra s doen in deze opdracht; namelijk het maximum bepalen van alle getallen die in de reeks voorbij zijn gekomen De truuk is grofweg als volgt: Voordat je de reeks gaat genereren, maak je een variabele aan om de hoogste waarde in op te slaan. Deze geef je een hele lage waarde (je hebt immers nog geen hoge waarde gezien, je moet de lijst nog maken..) Bij het genereren van de lijst check je steeds of het nieuwe getal misschien hoger is dan het hoogste dat je tot nu toe hebt gezien. Zo ja wordt dit het nieuwe hoogste getal, anders niet. Als je klaar bent met de lijst, heb je zo de hoogste gevonden en kun je die afdrukken. 7

Opdracht 4: Vullen (1,5 pnt): Lees heel goed de opgave, het is belangrijk dat je goed snapt hoe het spelletje werkt voordat je aan de code begint. Belangrijk om te onthouden: - Vakjes worden alleen horizontaal en verticaal als aangrenzend gezien - Het basisgebied start met de kleur van het vakje linksboven (en alle aangrenzende vakjes van dezelfde kleur) - Er wordt steeds gezocht naar de volgende vrije kleur. Dat is de kleur met het eerste vakje dat een andere kleur dan het basisgebied heeft (gezocht vanaf linksboven rij voor rij naar rechtsonder) - Deze vrije kleur wordt de nieuwe kleur van het basisgebied. Alle vakjes die deze kleur hebben en grenzen aan het basisgebied, worden nu ook onderdeel van het basisgebied. - Dit wordt herhaald totdat alle vakjes tot het basisgebied horen - Het antwoord waarom gevraagd wordt, is het aantal stappen dat hiervoor nodig was. Er zijn grofweg 2 strategiën om deze opgave op te lossen: Brute force (zeer inefficiënt, maar iets makkelijker te begrijpen) Recursief (slimme algoritmische truuk om het veel efficiënter te doen, is wat laster te begrijpen, maar interessant om te leren) Om te snappen hoe inefficiënt de brute-force methode hier is, bekijken we even hoeveel stappen er nodig zijn om het op te lossen: 1. Merk op dat er 100 vakjes zijn (10 * 10). 2. Om het basisgebied aan de start te bepalen moeten we het volgende doen: o Om te beginnen is het vakje linksboven basisgebied, de overige vakjes niet. o Nu vragen we een voor een aan alle vakjes of ze een buurman hebben die ook basisgebied is en of ze hetzelfde nummer hebben als het basisgebied. Zo ja wordt dat vakje ook basisgebied. o Omdat door de vorige stap het basisgebied misschien groter is geworden, moeten we dezelfde vraag nog een keer aan alle vakjes stellen. Immers, misschien hebben er nu wel een aantal een nieuwe basisgebied buurman. Dit zal (afhankelijk van het bord) maximaal 100(!) keer moeten gebeuren. o We hebben dus potentiëel 100 * 100 = 10000 stappen nodig om het eerste basisgebied te bepalen 3. Om het basisgebied uit te breiden, moeten we nu op zoek naar het volgende vrije getal (dus het eerste vakje met een andere kleur dan het basisgebied. Dat is niet lastig en kost maximaal 100 stappen (alle vakjes doorlopen vanaf linksboven tot we het volgende vrije vakje gevonden hebben) 4. Om het basisgebied uit te breiden moeten we nu ongeveer hetzelfde doen als in stap 2 en dat kost ons weer 100 * 100 = 10000 stappen. 8

5. Stap 3 en 4 moeten misschien wel 99 keer herhaald worden voor elke volgende uitbreiding van het gebien met een nieuw nummer Om al deze fasen te doorlopen en het hele bord te vullen zijn er dus grofweg 100 * 100 * 100 = 1000000 stappen nodig. In de informatica noemen we dit een complexiteit van N^3 (het aantal stappen is ongeveer het aantal vakjes tot de 3 e macht. (stel je hetzelfde spel voor met bijvoorbeeld 1000 vakjes *oef* 1 miljard stappen ) Wt heeft beide versies gebouwd. Zoals je aan de uit slag kunt zien, is de recursieve (afhankelijk van de testcase) vaak 10x zo snel! (Maar gelukkig is ook de brute-force versie nog ruim binnen de marge van 2 seconden uitvoertijd) Opdracht 4: Brute force strategie De brute force is niet efficiënt, maar wat makkelijker te begrijpen (zie stappen hierboven). Ik zal eerst hints geven om het zo aan te pakken. Hints voor de betere, recursieve aanpak staan verderop. 1. Het bord inladen. Voordat we een oplossing kunnen zoeken voor het probleem, zullen we eerst de invoer goed moeten verwerken en opslaan in variabelen in ons programma, zodat we weten hoe het bord eruit ziet en we bij kunnen houden wat het basisgebied is. De invoer bestaat uit 10 regels van elk 10 tekens. We geen deze invoer in een 2D list zetten : - Begin met een lege list met de naam bord - Maak een (for) loop die precies 10x wordt uitgevoerd. Elke stap van deze loop: o lees een regel uit de invoer (raw_input) en sla deze op in een tijdelijke variabele invoer. Dit zijn steeds 10 cijfers, maar we interpreteren ze als één lange string. o We kunnen de gelezen string converteren naar een list (die maakt er dus een lijst met 10 losse strings van elk 1 teken van) met het commando list(invoer) 9

o Met bord.append(invoer) plak je nu deze lijst van 10 tekens als sublijst aan de bord list Je hebt nu dus een list bord met daarin 10 keer een sublist van elke 10 strings van 1 teken lang. Test dit door je bord variabele te printen. Je zou zoiets als uitvoer moeten krijgen (met het voorbeeld bord als invoer: [['1', '3', '4', '6', '2', '4', '2', '3', '3', '1'], ['1', '2', '4', '3', '2', '2', '2', '4', '4', '5'], ['1', '4', '4', '2', '3', '2', '3', '4', '5', '5'], ['4', '4', '6', '5', '5', '5', '5', '5', '5', '4'], ['4', '3', '5', '1', '5', '2', '5', '1', '5', '3'], ['2', '1', '5', '5', '5', '1', '5', '5', '3', '3'], ['5', '5', '5', '5', '5', '5', '5', '5', '5', '5'], ['5', '2', '5', '6', '5', '4', '5', '3', '5', '4'], ['1', '6', '2', '3', '2', '3', '3', '2', '6', '6'], ['6', '6', '1', '3', '4', '1', '2', '4', '5', '5']] Omdat het heel veel gedoe is om elke keer dat je het programma wilt testen steeds die 10 regels in te voeren, kun je natuurlijk tijdelijk de hierboven gedrukte dubbele lijst rechtstreeks in je code zetten en het lezen van de invoer tijdelijk uitzetten. Als je daarnaa met andere borden wilt testen, moet je dit dus weer terugzetten. 2. Het basisgebied bijhouden. We moeten niet alleen weten welke nummers er in elk vakje van het bord staan, maar we moeten ook bijhouden welke vakjes al bij het basisgebied horen en welke niet. Gedurende ons programma moeten we deze administratie steeds bijwerken en zodra alle vakjes basisgebied zijn geworden, zijn we klaar. Om het basisgebied bij te houden, maken we een tweede lijst basisgebied met 10 sublijsten met elk 10 getallen (zodat we voor elk van de 100 vakjes precies een plekje hebben). Alle vakjes die bij het basisgebied horen, krijgen het getal 1 als inhoud, alle vakjes buiten het basisgebied geven we waarde 0. Aan het begin van ons programma weten we nog niet precies waar precies het basisgebied is, we weten alleen dat het vakje linksboven in ieder geval basisgebied is. Om te beginnen willen we dus een lijst die er zo uit ziet: [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] 10

Hier is dus het vakje linksboven (het eerste getal uit de eerste sublijst) gelijk aan 1 (=basisgebied), de rest is 0. Probeer deze basisgebied lijst in je code te zetten. Print vervolgens de lijst om te checken of hij klopt. 3. Het (start)nummer van het basisgebied bepalen. We moeten steeds bijhouden wat het nummer van het huidige basisgebied is. Dit nummer hebben we nodig om steeds de nieuw toe te voegen vakjes voor het basisgebied te selecteren. We houden dit bij in een variabele huidig_nummer. De startwaarde hiervan is eenvoudig. Deze is immers gelijk aan het nummer van het vakje linksboven. We gaan nu 3 functies schrijven die elk een deel van ons probleem oplossen. Vervolgens gebruiken we de functies in een slimme loop om het hele probleem te tackelen. Een probleem opdelen in deelproblemen is altijd een goede strategie bij dit soort grotere programmeeropgaven. 4. Grenzen checken Een deel van ons probleem vraagt om de mogelijkheid om van een vakje dat nog niet in het basisgebied hoort, te kunnen checken of het grenst aan het basisgebied. Omdat we deze vraag voor heel veel verschillende vakjes zullen gaan stellen, is het het handigst om een functie hiervoor te schrijven. Deze functie (laten we hem checkgrenzen() noemen) vraagt om een x en een y coordinaat (om het te checken vakje aan te geven. We checken nu of (minstens) 1 van de 4 buren van het vakje een basisgebied-vakje is. Zo ja returnt de functie True, zo nee, returnt de functie False Je krijgt dus zoiets als: def checkgrenzen(x,y): #is vakje x-1, y basisgebied? Zo ja return True #is vakje x, y-1 basisgebied? Zo ja return True #is vakje x+1, y basisgebied? Zo ja return True #is vakje x, y+1 basisgebied? Zo ja return True #anders: return False Let op! Niet elk vakje heeft 4 buren! Vakjes aan de rand hebben er maar 3 en vakjes in de hoeken zelfs maar 12 11

2. Als we hier geen rekening mee houden, gaan we foutmeldingen krijgen (een IndexError voor de error-handling-liefhebbers onder jullie ;) ). Je kunt immers niet de waarde opvragen van basisgebied[2][-1], of van basisgebied[10][5] (de vakjesnummers lopen maar van 0 tot en met 9). Bij het checken van de buren zul je dus met slimme if-else constructies alleen die buren moeten checken die ook echt bestaan (als een vakje bijvoorbeeld x-index 0 heeft, sla je dus het checken van de linkerbuur (x-1) over, want die bestaat immers niet) Vergeet niet je functie goed te testen voor je verder gaat. Als je zeker weet dat de functie goed werkt, hoef je later niet meer hier naar fouten op zoek: Check goed of je nergens buiten de list kijkt Controleer of je de goede antwoorden terug krijgt (check verschillende vakjes) 5. Functie 2: Vrije vakjes zoeken Een ander deelprobleem dat we moeten tackelen is het zoeken naar het volgende vrije vakje. Dat wil zeggen: nadat we het basisgebied hebben vergroot (zie stap 6), moeten we op zoek naar het kleurnummer van het eerstvolgende vakje dat nog niet bij het basisgebied hoort. Dit is niet heel lastig. We gaan vanaf linksboven alle vakjes langs (van links naar rechts en dan weer vanaf links op de volgende regel) tot we een vakje tegenkomen dat nog niet tot het basisgebied hoort. (We zoeken dus het eerste vakje dat op 0 staat in de basisgebied list). We gaan er meteen voor zorgen (je zult straks zien waarom dat handig is) dat onze functie ook meldt als er geen vrije vakjes meer zijn. Dat betekent namelijk dat we dan kennelijk alle vakjes in het basisgebied hebben en dan zijn we dus klaar! De functie heeft geen argumenten nodig en wordt dus ongeveer als volgt: def zoekvrijvakje(): # Maak een dubbele for-loop die de 100 vakjes in de juiste volgorde # doorloopt. Check van elk vakje of de waarde in de basisgebied-list # op 0 staat. Zodra je die een gevonden hebt, return je het nummer # dat in dat vakje staat (in de bord list). # Als je alle vakjes gehad hebt, maar niets gevonden hebt, dan # return je de waarde 0 (dat is een niet-bestaand kleurnummer) Als we straks de functie gebruiken weten we dus dat als we kleurwaarde 0 terug krijgen, we klaar zijn. Als we een ander kleurnummer terugkrijgen, kunnen we daarmee weer een stap zetten en het basisgebied verder uitbreiden. Test je functie weer goed voordat je verder gaat. Pas eens handmatig de basisgebied list aan om te testen of je functie werkt voor verschillende waardes/vormen van het basisgebied. 12

6. Functie 3: Het basisgebied uitbreiden op basis van het nieuwe vrije nummer Bij stap 5 heb je een functie gemaakt om het volgende vrije nummer te zoeken. Op basis van dit nummer willen we het basisgebied uitbreiden met alle vakjes die dit nummer hebben en grenzen aan het huidige basisgebied. Omdat we dit ook een aantal keer moeten doen, schrijven we ook hier een functie voor. Deze functie heeft als argument het nummer van de nieuwe vrije kleur: def breiduit(kleurnummer): # doorloop alle vakjes en doe achtereenvolgens het volgende: # - check of het vakje buiten het basisgebied zit # - Zo ja: check of het vakje grenst aan het basisgebied door de # checkgrenzen() functie te gebruiken uit stap 4 # - Zo ja: check of het vakje een kleur heeft die gelijk is aan het # gezochte kleurnummer. # - Zo ja: voeg het huidige vakje toe aan het basisgebied # Herhaal het bovenstaande 100 keer (dit is het brute-force # gedeelte). Elke wijziging van het basisgebied kan een nieuwe # wijziging tot gevolg hebben. 100 keer herhaling zorgt ervoor dat # je zeker weet dat je alle wijzigingen (er zijn immers 100 vakjes) # hebt doorgevoerd. 7. Alles laten samenwerken Je hebt nu de bouwstenen om de hele opgave te tackelen. We gaan nu de 3 functies uit de vorige stappen gebruiken om de puzzel op te lossen. Grofweg doe je dat als volgt: Zoek steeds het volgende vrije vakje (met je functie uit stap 5). Zolang er nog zo n vakje is: o Gebruik de breiduit() functie om het basisgebied uit te breiden op basis van dit vakje o Houdt steeds het aantal stappen bij Als je klaar bent, druk het aantal getelde stappen af. Opdracht 4: Recursieve strategie Deze strategie is voor de betere puzzelaars en je hebt hiervoor dus recursie nodig. Opgave A5 is zelfs niet te doen zonder recursie. Bij de tips van opgave 5 hieronder staat een korte introductie tot recursie. Bestudeer die eerst en kom dan hier terug. We gaan zorgen voor een soort olievlek -effect. Dat wil zeggen: bij het uitbreiden van het basisgebied gaan we niet heel lomp een-voor-een alle vakjes 100x vragen of ze hun toetsand moeten veranderen. We gaan nu aan alle vakjes van het basisgebied vragen om hun eventuele buren te vragen hun status in basigebied te veranderen als ze het juiste nummer hebben. Deze vragen op hun beurt weer aan hun buren hetzelfde. Zo vraag je vakjes maar 1x in plaats van 100x en loop je toch niets mis. 13

Tips en trucs om je op weg te helpen met een recursieve A4 oplossing: - Het begin is identiek aan stap 1, 2 en 3 van de brute-force methode - De functie zoekvrijvakje() uit stap 5 van de brute-force heb je ook nodig - De truuk zit hem in een efficiëntere (recursieve) versie van de breiduit() functie - We vragen elke stap aan alle vakjes van het basisgebied om deze recursieve functie uit te voeren. Zij zullen dan het olievlek effect in gang zetten voor deze stap - De recursieve functie werkt ongeveer als volgt: def breiduit(kleur, x, y): # argumenten: kleur is de gezochte nieuwe basiskleur, x en y # zijn de coordinaten van het vakje dat we op dit moment # aanspreken # Stap 1: check of je zelf (dus het vakje met coördinaten x en # y) bij het basisgebied hoort # Zo ja: vraag aan al je 4 buren (let op de randen: zie brute- # force stap 4) die geen basisgebied zijn om dit ook te doen. # Dat wil zeggen: voer deze breiduit() functie nu ook # (recursief) uit op de 4 vakjes om je heen (dus met andere x # of y coördinaten) # Stap 2: als je niet bij het basisgebied hoort, check dan of # je zelf het gewenste kleurnummer hebt (dan is je deze vraag # gesteld door een buurman die wel basisgebied was of is # geworden.) # Zo ja: Maak jezelf tot onderdeel van het basisgebied. En # vraag aan al je 4 buren die geen basisgebied zijn om weer # deze functie uit te voeren (geef de vraag door aan je buren # als het ware) Opdracht 5: Boomcentrum (1 pnt) Introductie recursie Voor het oplossen van deze opgave heb je een programmeerprincipe nodig dat recursie heet (bij opgave 4 was het een optie, hier niet..). Recursie is programmeren met een functie (def) die zichzelf aanroept (en daarbij dus zichzelf weer aanroept, die daarbij zichzelf weer aanroept, etc.) Voor een introductie op recursie, kijk eens hier: http://programarcadegames.com/index.php?chapter=recursion&lang=nl#section_19 Een bekend voorbeeld van recursie is het berekenen van de Fibonacci reeks (wat we vorig jaar al zonder recursie hebben gedaan in Wt Python opgave 9). Hier is een recursieve oplossing voor het Fibonacci probleem: def fib(n): if n==1 or n==2: 14

return 1 else: return fib(n-1) + fib(n-2) Bekijk (en test) het voorbeeld eens om goed te snappen wat er gebeurt. Vergelijk de recursieve oplossing met de gewone (iteratieve) oplossing die je vorig jaar hebt gemaakt (hier zijn Wt s uitwerkingen overigens), vraag Wt eventueel om extra uitleg om de recursieve versie goed te snappen. De opgave Nu je weet wat recursie is, terug naar opgave A5. Grofweg komt de oplossing van deze opgave op het volgende neer: - We maken een lijst met voor elk punt een sublijst met daarin de afstand tot alle andere punten. (Die afstand is bij de start nog niet bekend, maar die gaan we opbouwen) - De direct verbonden punten (zoals opgegeven bij de inpiut) kunnen we met een afstand 1 in de afstandlijsten opnemen - We gaan nu recursief vanuit elk punt een bericht naar alle buren sturen met de afstand van deze buur tot de originele afzender. Alle buren geven dit bericht weer door aan hun buren (met een afstand +1) en die geven het weeer aan hun buren, etc. - Op deze manier vertelt elk punt zijn afstand aan alle andere punten. - Als alle punten alle afstanden naar andere punten kennen, dan kunnen we op zoek naar het punt of de punten met de kleinste afstand tot alle andere punten. Dit is het antwoord dat we moeten geven. Stap 1: invoer opslaan We moeten weer een slimme (ja alweer een slimme ) manier verzinnen om onze adminstratie bij te houden. Wt doet het als volgt. We moeten van elke punt opslaan met welke andere punten deze verbonden is (in hoeveel stappen). Het handigst is om een connectie matrix te maken. Dat is een sjiek woord voor lijst met daarin een sublijst voor elk punt van de boom. Elke sublijst houdt bij wat de afstand van een punt is (in stappen) tot elk ander. Voor het voorbeeld zou je connectiematrix er na het lezen van de invoer zo uit zien: [-1, 0, 0, 1, 0, 0] [0, -1, 0, 1, 0, 0] [0, 0, -1, 1, 0, 0] [1, 1, 1, -1, 1, 0] [0, 0, 0, 1, -1, 1] [0, 0, 0, 0, 1, -1] - De eerste lijst is het eerste punt, de tweede het tweede punt, etc. 15

- Een 0 betekent niet direct verbonden met het punt op die positie (dus die afstand is nu nog onbekend) - Een 1 betekent direct verbonden met het punt op die positie (zoals ingelezen uit de invoer) - Een -1 staat op de plek van het punt zelf ( je kunt niet verbonden zijn met jezelf) Wat betreft het verwerken de input. De eerste regel input geeft aan hoeveel punten er zijn. De regels er na (het aantal punten -1) geven de connecties aan. Maak een loop die precies het juiste aantal regels inleest. Let op dat je voor elke regel input op 2 plekken in de matrix een 1 zet. (Als het ene punt met het andere verbonden is, geldt dat natuurlijk ook andersom!) Tip: gebruik het python split commando: connectie = raw_input().split(" ") Dit leest de input en splitst de string in een lijst (met de spatie als splitspunt) Zo kun je makkelijk de 2 punten van elke connectieregel inlezen: connectie[0] en connectie[1]. Stap 2: Een recursieve functie die de afstand van een punt doorstuurt naar alle andere punten Zoals gezegd is de kern van deze opgave het maken van een recursieve functie die alle punten op de hoogte stelt van hun afstand van een specifiek punt. Je functie ziet er ongeveer als volgt uit: def vertel_afstand(start_punt, huidig_punt, vorig_punt, afstand): # Deze functie heeft 4 argumenten: # start_punt: dit is het punt waarvan we de afstand willen doorgeven # deze blijft constant gedurende de recursie # huidig punt: dit is de plek waar het bericht nu is. Dit punt kan # nu de afstand tot het startpunt opslaan en recursief het bericht # aan zijn buren sturen # vorig_punt: van welk punt kwam dit bericht? Dit moeten we weten om # te voorkomen dat het bericht ook weer terug gaat naar de # afzender # afstand: hoe ver is het start_punt van het huisig_punt verwijderd? # Bij elke recursiestap wordt dit 1 hoger # check of bij huidig_punt al bekend is wat de afstand is tot # start_punt. # zo nee: sla de huidige afstand op in de matrix # # vraag recursief aan al je buren (behalve vorig_punt!) om deze # vertel_afstand functie uit te voeren. Hierbij wordt afstand 1 # hoger gezet dan hij nu is (we gaan immers 1 punt verderop in de # boom en daarmee wordt de afstand tot het bronpunt 1 groter) 16

Stap 3: Laat de recursie los op elk punt We gaan nu een voor een een recursieve olievlek starten in elk van de punten, zodat elk punt zijn afstand doorgeeft aan alle endere punten in de boom. Probeer zelf te bedenken wat de startwaarden voor de 4 argumenten van de vertel_afstand() functie moeten zijn. Stap 4: Zoek het boomcentrum We hebben nu onze hele afstandmatrix gevuld, dus kunnen we het boomcentrum bepalen. We moeten dus op zoek naar het/de punt(en) met het laagste afstandmaximum. Dat wil zeggen: we kijken van elk punt wat de grootste afstand tot de andere punten is. De punt(en) die hier de laagste waarde hebben, zijn het boomcentrum. - Doorloop de afstandslijst voor elk punt op zoek naar het maximum - Sla steeds dit maximum op in een lijst - Zoek in deze lijst wat de laagste waarde is. - Zoek op welke punten deze laagste waarde hebben. Dat is je antwoord op deze opgave Succes met C1 t/m C4! 17