PO: Informatica Olympiade 2013-2014

PO: Informatica Olympiade 2013-2014
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:
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 zijn ingeleverd
bij de NIO voor 15 januari.
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. 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 eind op weg , je kunt
dan zelf de opgaven van categorie B, C en D nog maken voor meer punten). Meer details over
hoe je meedoet en welke voorwarden er zijn, vind je in het document van de NIO op de
informaticasite (en op www.informaticaolympiade.nl). Wt helpt je natuulijk graag hiermee als je
besluit mee te doen.
Inleveren en beoordeling:
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
leveren. Als je toch allebei wilt deelnemen, zul je verschillende versies van je oplossingen
moeten maken.)
Elke volledig correcte opgave is 2 punten waard (de opgaven worden wel steeds moeilijker).
Deels correcte oplossingen van een opgave leveren een deel van de 2 punten op. Je zult dus alle
5 de opgaven perfect moeten maken voor een 10.
Je levert bij Wt je gemaakte Javaprogramma’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
Wt/2014
1
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.
Je levert alle onderdelen van de PO in in een .zip file bij de opdracht die openstaat in de ELO. Je
hoeft per groepje uiteraard maar 1 keer in te leveren.
Uiterlijke inleverdatum: Zondag 30 November om 22:00 uur
Zie de volgende bladzijden voor tips, hints en uitleg om je te helpen de opgaven te tackelen.
Wt/2014
2
Aanwijzingen bij de opgaven van de NIO 2014-2015
Hieronder volgen eerst wat algemene aanwijzingen om je programma’s geschikt te maken voor
de NIO opgaven. Daarna volgen specifieke tips voor opgaven A1 t/m A5. Opgaven C1 en C2 zul je
helemaal zelf moeten uitvogelen.
Een ‘kaal’ Java programma
We hebben al gewerkt met JavaEditor en met Greenfoot (dat is een uitbreiding van de
programmeertaal Java). Javacode ken je dus al en voor de NIO kun je gewoon JavaEditor
gebruiken. Voor de NIO opgaven werken we alleen niet met applets zoals we vorig jaar hebben
gedaan, maar met ‘kale’ Java programma’s.
Het grootste verschil is dat een ‘kaal’ javaprogramma geen grafische interface heeft (dus geen
knoppen en tekstvelden etc.). Het werkt slechts op de commandline (console/DOS venster). Via
dat console venster kan tekstuele invoer en uitvoer worden gedaan. ‘Kale’ Javaprogramma’s
hebben dus ook geen voorgedefinieerde objecten zoals Greenfoot die heeft.
Je maakt een kaal javaprogramma in JavaEditor door te kiezen
voor “Bestand”->”Nieuw“->”Console”:
Een leeg console Javaprogramma bevat een klein stukje
standaardcode:
Je programma bestaat slechts uit een public class <bestandsnaam> (De klasse waarin je hele
programma zit) en een methode: public static void main(String[] args) Deze methode wordt
standaard uitgevoerd als je programma start. Hier kun je dus je eigen code toevoegen.
Wt/2014
3
Invoer lezen en schrijven
Om ons Java programma geschikt te maken voor het lezen van invoer en het schrijven van
uitvoer, moeten we een paar dingen aan de code wijzigen. Deze code krijg je van mij cadeau,
zodat je alleen op het oplossen van de problemen zelf hoeft te focussen. Pas je code aan zodat
hij er zo uitziet (let op dat je de naam van de Class niet verandert (Bij mij heet hij
Olympiade_opdr1). Deze moet overeenkomen met de bestandsnaam van je programmacode!):
Er zijn een paar dingen bijgekomen/veranderd:
 Op de eerste regel importeren we een Java bibliotheek die het mogelijk maakt om met
invoer en uitvoer te werken
 We declareren een object van de klasse BufferedReader. We hebben deze de naam
“reader” gegeven. Deze reader kunnen we nu in ons programma gebruiken om regels in
te lezen uit de invoer van het toetsenbord.
 De main methode is uitgebreid met de code throws IOException. Dit is door Java
verplicht als je met invoer en uitvoer werkt. Hiermee kunnen eventuele fouten in deze
invoer en uitvoer worden afgehandeld.
 In de body van de main methode hebben we als voorbeeld een stukje invoer en uitvoer
gedaan.
Wt/2014
4
Als je nu je programma uitvoert (dat doe je met de groene “play” knop bovenaan weet je
nog?) opent er een command venster met een knipperende cursor. Je kunt nu een regel tekst
intypen gevolgd door een enter. De tekst wordt ingelezen in je programma (en opgeslagen in de
String variabele s).
Je ziet je invoer meteen nog een keer op het scherm verschijnen. Dat komt omdat we met
System.out.println(s) de inhoud van variabele s nog een keer op het scherm
afdrukken.
Je programma eindigt nu meteen (en vraagt je om een toets in te drukken om het console
scherm te sluiten).
Aanpak Olympiadeopdracht A1
Lees eerst goed de opdrachtomschrijving van NIO opgave A1. Maak (als je dat nog niet gedaan
hebt) een nieuw javaprogramma aan en maak deze geschikt voor in- en uitvoer volgens de
aanwijzingen op de vorige bladzijden.
Bij lastigere programmeeropgaven is het altijd belangrijk het probleem in kleine stapjes te
tackelen. Test steeds elke stap voordat je naar de volgende gaat. Dan weet je zeker dat je
tussendoor geen fouten maakt. Zo werk je langzaam naar de oplossing toe. Hieronder een
suggestie van stappen die je naar de oplossing leiden:
-
Stap 1: Lees het invoer getal. Om te testen of het gelukt is, schrijf je het gelezen getal
meteen naar de uitvoer.
-
Stap 2: Converteer het invoergetal naar int en maak een loopje (while of for) die precies
evenveel stappen heeft als het invoergetal aangeeft. Test dit door in elke stap van je
loop een regel testuitvoer te geven. Als het goed is schrijft je programma nu precies
zoveel regels als het invoergetal aangeeft.
-
Stap 3: Dit is de lastigste stap en de uitdaging van deze opgave. Je moet nu de
kerstboom gaan “opbouwen”. Hier zit natuurlijk een patroon in en dat zul je moeten
gebruiken. Een paar hints om je op weg te helpen:
o
Wt/2014
Je hebt in stap 2 een loop gemaakt gelijk aan het aantal regels dat de kerstboom
hoog is. Dit noemen we de hoofdloop. Begin elke stap van de hoofdloop met
een lege String. Vul deze langzaam met het juiste aantal - en *. Hiervoor heb je
nog meer kleine loops nodig (zie volgende hint). Als je een regel zo gevuld hebt,
druk je hem af op het scherm en begint de volgende stap van de hoofdloop.
5
o
Om een aantal keer achter elkaar hetzelfde teken in een String te zetten kun je
het volgende doen:
String regel = "";
for (int i=0; i<10; i++) {
regel += "x";
}
Bovenstaande code heeft als resultaat dat de String regel gevuld is met
“xxxxxxxxxx” (10 keer “x”)
o
-
Het aantal - en * in elke regel van de kerstboom is afhankelijk van 2 dingen:
 Het invoergetal
 De hoeveelste regel is dit?
Gebruik deze info om de binnenste loops te maken.
Stap 4: Je hebt nu de “bovenkant” van de kerstboom gemaakt. Jehoeft nu alleen de
“stam” er nog onder te plakken. Dit is nu eenvoudig, want de stam is hetzelfde als de
eerste regel van de kerstboom.
Aanpak Olympiadeopdracht A2
Lees eerst goed de opdrachtomschrijving van NIO opgave A2. Maak (als je dat nog niet gedaan
hebt) een nieuw javaprogramma aan en maak deze geschikt voor in- en uitvoer volgens de
aanwijzingen op de vorige bladzijden.
-
Stap 1: lees het invoergetal. Test dit weer door het getal meteen naar de uitvoer te
schrijven.
-
Stap 2: zorg dat je programma invoer blijft lezen net zolang tot er een 0 wordt
ingevoerd. Daarvoor kun je onderstaande code gebruiken:
// lees de eerste regel van de invoer:
String invoer = reader.readLine();
//zolang de invoer niet gelijk is aan 0:
while (!invoer.equals("0")) {
// doe iets met de invoer
...
...
// lees de volgende regel:
invoer = reader.readLine();
}
Wt/2014
6
-
Stap 3: Converteer steeds het invoer getal naar een int en gebruik een if om te
controleren of dit getal even of oneven is (gebruik modulo %). Druk nu steeds het woord
“even” of “oneven” af op het scherm om je code te testen. Als je niet meer weet hoe de
modulo (%) werkt, spiek in het Javaboek op bladzijde 65.
-
Stap 4: Je kunt nu herhaaldelijk invoer lezen en bepalen of deze even of oneven is. Het
zou nu eenvoudig moeten zijn om een totaal bij te houden van de kwadraten van alle
oneven invoer. Zodra je programma een 0 als invoer krijgt, kun je dit totaal op het
scherm afdrukken. Test het goed en controleer steeds of je uitvoer klopt.
Aanpak Olympiadeopdracht A3
Lees eerst goed de opdrachtomschrijving van NIO opgave A3. Maak (als je dat nog niet gedaan
hebt) een nieuw javaprogramma aan en maak deze geschikt voor in- en uitvoer volgens de
aanwijzingen op de vorige bladzijden.
Deze opdracht zijn eigenlijk 4 opdrachten in een, die je los van elkaar kunt zien. Twee hiervan
hebben we letterlijk gedaan bij de Javalessen in klas 5. Laten we die eerst tackelen:
-
Stap 1: De eerste opdracht is het teruggeven van de lengte van de invoer. Dit is
gemakkelijk te doen met 1 enkel javacommando. Check hoe je de lengte van een String
opvraagt in het Javaboek pagina 70.
-
Stap 2: We slaan de tweede en derde opdracht even over, omdat we de vierde opdracht
ook bijna letterlijk uit het Javaboek kunnen overnemen. Kijk op pagina 70 van het
Javaboek om te kijken hoe je een String omdraait.
-
Stap 3: We gaan verder met opdracht 2, omdat deze het makkelijkst is. Je zult net als bij
de vorige stap met een loop langs alle letters van de invoer moeten. Java heeft een
ingebouwd commando om van een teken te kijken of het een hoofdletter is. Die kunnen
we goed gebruiken:
Character.isUpperCase()
Deze methode heeft 1 nadeel: hij werkt op variabelen van het type char en niet op
String. Een char is een Java type dat we nog niet kennen. Het bevat 1 enkel ASCII
teken. Gelukkig is er ook een commando om een char uit een String te halen:
String mijnString = "Ik ben een voorbeeld";
char letter = mijnString.charAt(3);
In het voorbeeld bevat de variabele letter nu het teken op positie 3 uit
mijnString, dus een ‘b’ (let op we beginnen te tellen bij 0, dus positie 3 is de 4e
letter!)
Wt/2014
7
We zouden nu kunnen doen om te checken of het een hoofdletter is:
if (Character.isUpperCase(letter)) {
...
}
Zorg nu dus dat je 1 voor 1 alle letters uit de invoer haalt en kijkt of het een hoofdletter
is. Houd in een teller bij hoeveel hoofdletter je tegenkomt en druk deze uiteindelijk op
het scherm af.
-
Stap 4: Tot slot moeten we het aantal verschillende letters tellen.
o
Java heeft een commando om op te vragen of een String een bepaald teken
bevat. Die kunnen we goed gebruiken. Een voorbeeld om dat commando te
illusteren:
String mijnString = "Ik ben een voorbeeld";
if (mijnString.contains("q")) {
...
}
In het voorbeeld vragen we in een if of mijnString de letter q bevat.
o
Een naieve manier om dit probleem te tackelen is om van elk mogelijk teken te
vragen of deze in de invoer zit en zo alle verschillende tekens te tellen. Dit is erg
omslachtig en je weet niet precies welke tekens zijn toegestaan (er zijn ook
namen met trema’s erin bijvoorbeeld, zoals Daniël). Dat zijn wel erg veel ifs...
o
Een slimmere manier is als volgt:
 Maak een lege String aan met de naam uniekString
 Doorloop letter voor letter de invoer (zoals bij stap 2)
 Kijk steeds of de huidige letter van de invoer al voorkomt in
uniekString. Zo nee: voeg de huidige letter toe aan
uniekString.
 Als je alle letters van de invoer hebt gehad, bevat uniekString
alleen maar verschillende letters
 Je hoeft nu alleen maar de lengte van uniekString op te vragen
voor het goede antwoord.
Aanpak Olympiadeopdracht A4
Lees eerst goed de opdrachtomschrijving van NIO opgave A4. Maak (als je dat nog niet gedaan
hebt) een nieuw javaprogramma aan en maak deze geschikt voor in- en uitvoer volgens de
aanwijzingen op de vorige bladzijden.
Wt/2014
8
De invoer voor deze opdracht bestaat uit 4 regels van 4 tekens (de tekens 0 of 1). Na het
accepteren van deze invoer, moet je horizontaal en verticaal gaan zoeken in deze invoer. Dat
lukt je alleen als je de invoer op de juiste manier opslaat: in een array. Een tweedimensionaal
array om precies te zijn.
Hoe zat dat ook alweer met die arrays? Misschien is dit een goed moment om de stof daarover
nog eens te bekijken. Lees Wt’s stof over arrays van vorig jaar en dan met name pagina 4 over
2D arrays.
Een opmerking over deze opgave: Als je goed naar het voorbeeld kijkt dat bij de opgave staat, zie
je dat grotere reeksen voor gaan op kleinere. Dat wil zeggen als op een regel staat 0111, dan is
dat een reeks van 3 x 1 en niet 2 reeksen van 2 x 1. Het is dus belangrijk om per regel de grote
reeksen eerst te checken. Pas als een grote reeks niet gevonden is, ga je kijken of er misschien
een kleinere reeks te vinden is.Houd dit in je achterhoofd bij het stappenplan
Een stappenplan om deze opgave te tackelen:
-
Stap 1: Zoals gezegd zal de invoer in een 2D array moeten worden opgeslagen. Omdat
elk “vakje” van de invoer uit 1 teken bestaat (0 of 1) ligt het voor de hand om een array
van het type char te gebruiken:
char[][] matrix = new char[4][4];
Zo creer je een 2D char array, met 4 elementen in beide richtingen. Precies groot
genoeg om de 4x4 invoer in op te slaan. Gebruik een loop om de 4 regels van de invoer
1 voor 1 te accepteren en de losse tekens (gebruik .charAt() ) op te slaan op de
juiste plek in het array.
Om te testen of het goed is gegaan kun je het beste (met weer een loop) de inhoud van
je array op het scherm afdrukken. Deze zou dan dus identiek moeten zijn aan de
gegeven invoer.
-
Stap 2: Maak 6 int tellers aan die je elk op 0 initialiseert. Deze 6 tellers houden bij
hoeveel reeksen van elke soort (2x0, 2x1, 3x0, 3x1, 4x0, 4x1) je tot nu toe hebt
gevonden. Met slimme loops gaan we zometeen door de invoer heen. Als we een reeks
vinden, verhogen we de juiste teller. Als we dan klaar zijn met de invoer bekijken,
bevatten de 6 tellers het goede antwoord en kunnen we deze op het scherm afdrukken.
-
Stap 3: Begin met checken op reeksen van 4 x 0 of 4 x 1. Dit moet natuurlijk zowel
horizontaal als verticaal gecheckt worden. Om horizontaal te kijken of er een reeks van
4 x 0 is. Moeten we simpelweg kijken of alle 4 de elementen van een regel gelijk zijn aan
0. Zoiets als dit:
Wt/2014
9
if (matrix[0][0]=='0' && matrix[0][1]=='0' && matrix[0][2]=='0' && matrix[0][3]=='0') {
…
…
}
Met deze voorbeeldcode checken we of de eerste horizontale rij (rij 0) uit allemaal 0en
bestaat. Dit moeten we natuurlijk checken voor elk van de 4 rijen. Dit kan slim met een
loop. Op een vergelijkbare manier check je de verticale kolommen.
Om te testen of je het goed hebt gedaan, zou ik na het checken het aantal gevonden
reeksen afdrukken. JE kunt makkelijk op het oog natellen of je antwoord (en daarmee je
code) klopt.
-
Stap 4: Als je een rij of kolom hebt gecheckt op een reeks van 4 en deze niet hebt
gevonden, dan moet je gaan checken op een reeks van 3. Dit gaat natuurlijk
vergelijkbaar met checken op een reeks van 4. Let op det er op 2 manieren een reeks
van 3 kan zijn, namelijk aan het begin of aan het eind van een rij of kolom
-
Stap 5: Als je een rij of kolom hebt ook hebt gecheckt op een reeks van 3 en deze niet
hebt gevonden, rest nog om te checken op reeksen van 2. Dit gaat wederom
vergelijkbaar. Let op dat er op 3 manieren een reeks van 2 in een rij of kolom kan zitten.
Namelijk aan het begin, in het midden en op het einde.
Verzin een paar testcases en check of je programma het goede antwoord geeft bij alle cases.
Aanpak Olympiadeopdracht A5
Lees eerst goed de opdrachtomschrijving van NIO opgave A5. Maak (als je dat nog niet gedaan
hebt) een nieuw javaprogramma aan en maak deze geschikt voor in- en uitvoer volgens de
aanwijzingen op de vorige bladzijden.
Opgave 5 is met afstand de pittigste. Je hebt in ieder geval de volgende arrays nodig:
- Een (2D) array om de uitgebrachte stemmen per deelnemer op te slaan
- Een array om per stemronde te turven hoeveel stemmen elke kandidaat krijgt
- Een array om bij te houden welke kandidaten nog verkiesbaar zijn (zodat je weet hoe je
de stemmen moet tellen in elke ronde
Al deze arrays moeten variabel van lengte zijn, omdat je van te voren niet weet hoeveel
kandidaten en deelnemers er zijn.
Je zult vervolgens met een slimme loop net zoveel stemrondes moeten doorlopen als nodig is
om een winnaar te kiezen. Per ronde waarin geen winnaar gevonden is, moet je de verliezer af
laten vallen ,zodat deze niet meer meetelt in de volgende ronde.
Voor nu zijn dit alle hints. Op verzoek kan Wt de uiteg bij deze opgave nog uitbreiden.
Wt/2014
10
Nuttige links
Olympiade site: http://www.informaticaolympiade.nl
Uitleg over arrays: http://www.stedgymdenbosch.nl/subsites/informatica/data/veilig/Wt%20%20Arrays%20en%20sorteren.pdf
Java voor beginners met goede tutorials: http://www.homeandlearn.co.uk/java/java.html
Goede site om Java dingen op te zoeken: http://www.leepoint.net/notes-java/index.html
Enigma Java informatieboek:
http://www.sgdb.nl/subsites/informatica/data/veilig/deel1/infboek/4%20VisProg%20infboek.p
df
Enigma Java werkboek:
http://www.sgdb.nl/subsites/informatica/data/veilig/deel1/verwboek/4%20VisProg%20verwbo
ek.pdf
Wt uitleg Java arrays: http://www.sgdb.nl/subsites/informatica/data/veilig/Wt%20%20Arrays%20en%20sorteren.pdf
Wt/2014
11