Basis¶
De basis heeft twee delen. Begin na het eerste college met De nacht van het nijlpaard en na het tweede college met De uitslag van de schoolrun.
De nacht van het nijlpaard¶
Nijlpaarden houden van een goede maaltijd, maar ze willen wel ruimte om zich heen. Elke nacht zet de kok maaltijden op een lange tafel. Aan één kant van de tafel zijn de plaatsen genummerd: 1, 2, 3, enzovoort. Op een plaats kan meer dan één maaltijd staan. De ceremoniemeester bepaalt hoeveel ruimte er tussen de nijlpaarden moet zijn, en zorgt dat er zoveel mogelijk nijlpaarden mee-eten. In deze opgave reken je uit hoeveel dat er zijn.
De regel¶
Een nijlpaard gaat zitten op een plaats waar een maaltijd staat. De afstand tussen twee nijlpaarden is het verschil van hun plaatsnummers, en die moet minstens gelijk zijn aan de afstand die de ceremoniemeester heeft gekozen. Op één plaats zit hoogstens één nijlpaard.
Gekozen afstand |
Plaatsen met een maaltijd |
Zoveel nijlpaarden eten mee |
Bijvoorbeeld op |
|---|---|---|---|
1 |
2, 3, 3 |
2 |
2 en 3 |
2 |
1, 3, 7 |
3 |
1, 3 en 7 |
4 |
1, 3, 5, 10, 12 |
3 |
1, 5 en 12 |
Bij afstand 2 zit er dus minstens één lege plaats tussen twee nijlpaarden. In het laatste voorbeeld kunnen er geen vier mee-eten: welke vier plaatsen je ook kiest, er liggen er altijd twee minder dan 4 uit elkaar.



De plaatsen staan in deze opgave altijd oplopend in de lijst.
Wat je gaat maken¶
Stap |
Functie |
Doet |
Wat je oefent |
|---|---|---|---|
1 |
|
liggen twee plaatsen ver genoeg uit elkaar? |
geen recursie |
2 |
|
haal de plaatsen weg die te dicht bij een nijlpaard liggen |
één recursieve aanroep |
3 |
|
hoeveel nijlpaarden kunnen er hoogstens mee-eten? |
use it or lose it |
Stap 1: far_enough(a, b, distance)¶
Geeft True als plaats b minstens distance verder ligt dan plaats a, en
anders False. b is nooit kleiner dan a. Deze functie heeft geen recursie
nodig.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
|
|
Hint
Het verschil tussen de twee plaatsen is b - a.
# jouw oplossing
assert far_enough(1, 3, 2) == True
assert far_enough(2, 3, 2) == False
assert far_enough(3, 3, 1) == False
assert far_enough(5, 10, 5) == True
Stap 2: drop_too_close(place, places, distance)¶
Er zit een nijlpaard op plaats place. places is een oplopende lijst met de
plaatsen erna. Geeft de lijst terug zonder de plaatsen aan het begin die te dicht
bij place liggen. Vanaf de eerste plaats die ver genoeg ligt, blijft de lijst
staan.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
|
|
Hint
Gebruik far_enough uit stap 1. Ligt de eerste plaats ver genoeg, dan ben je
klaar: dan geef je de hele lijst terug. Omdat de lijst oplopend is, liggen de
plaatsen daarna nog verder weg.
# jouw oplossing
assert drop_too_close(1, [3, 7], 2) == [3, 7]
assert drop_too_close(3, [3, 5, 8], 4) == [8]
assert drop_too_close(1, [3, 5, 10, 12], 4) == [5, 10, 12]
assert drop_too_close(5, [6, 7], 3) == []
assert drop_too_close(5, [], 2) == []
Stap 3: hippo_dinner(distance, places)¶
places is een oplopende lijst met de plaatsen waar een maaltijd staat. Geeft
terug hoeveel nijlpaarden er hoogstens kunnen mee-eten als de afstand tussen
twee nijlpaarden minstens distance moet zijn. Gebruik recursie.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
|
|
|
|
Hint
Kies bij de eerste plaats, zoals bij subset in het
college:
Use it: er gaat een nijlpaard op de eerste plaats zitten. Dat is er één, plus zoveel als er passen op de rest, nadat je met
drop_too_closede plaatsen hebt weggehaald die te dicht bij de eerste liggen.Lose it: op de eerste plaats gaat niemand zitten. Dan tel je zoveel als er op de rest passen.
Geef het grootste van de twee terug.
# jouw oplossing
assert hippo_dinner(1, [2, 3, 3]) == 2
assert hippo_dinner(2, [1, 3, 7]) == 3
assert hippo_dinner(4, [1, 3, 5, 10, 12]) == 3
assert hippo_dinner(3, [4]) == 1
assert hippo_dinner(3, []) == 0
Tot slot¶
Bij afstand 4 en maaltijden op 1, 3, 5, 10 en 12 eten er drie nijlpaarden mee.
Of je de eerste plaats moet gebruiken, kon hippo_dinner niet vooraf weten. Pas
door beide keuzes te proberen vond de functie het beste antwoord, precies zoals
subset in het college.
hippo_dinner zegt hoeveel nijlpaarden er mee-eten, maar niet op welke plaatsen.
Hoe je ook de gekozen elementen terugkrijgt, zie je aan het eind van het
tweede college.
(Informatica Olympiade 2023-2024)
De uitslag van de schoolrun¶
Op de sportdag lopen de leerlingen een rondje van drie kilometer. Na afloop moet
er een uitslag komen: wie was het snelst, wat is de ranglijst, en wie wint bij de
jeugd, onder de 18? In deze opgave schrijf je die functies. In stap 4 tot en met 7 geef je een
andere functie mee: aan max, min of sorted, of aan een functie die je zelf
schrijft.
De uitslag¶
De uitslag is een lijst van lijsten. Elke deelnemer is een lijst met drie elementen:
Index |
Betekenis |
Voorbeeld |
|---|---|---|
|
naam |
|
|
leeftijd in jaren |
|
|
tijd in seconden |
|
Noor liep het rondje dus in 754 seconden: 12 minuten en 34 seconden. Wie de
kleinste tijd heeft, was het snelst. De cel hieronder zet de uitslag klaar in
RESULTS. Voer hem eerst uit.
RESULTS = [
["Noor", 17, 754],
["Sem", 19, 698],
["Lotte", 18, 698],
["Yara", 16, 812],
["Finn", 21, 745],
]
Wat je gaat maken¶
Stap |
Functie |
Doet |
Wat je meegeeft |
|---|---|---|---|
4 |
|
de naam van de snelste |
een lambda-functie aan |
5 |
|
de namen van snel naar langzaam |
een lambda-functie met een sleutel van twee delen aan |
6 |
|
de deelnemers die aan een voorwaarde voldoen |
een functie als argument aan je eigen functie |
7 |
|
de naam van de snelste die aan een voorwaarde voldoet |
een functie als argument, die je weer aan |
8 |
|
maximaal drie namen onder een leeftijdsgrens |
je kiest zelf aanpak en opbouw |
opdracht 1 |
de functies van stap 4 tot en met 7 |
wat moet er veranderen bij gelijke tijden? |
je beschrijft de wijziging, zonder code |
Stap 4: fastest(results)¶
Geeft de naam van de deelnemer met de kleinste tijd. results is niet leeg.
Hebben twee deelnemers dezelfde tijd, dan wint wie het eerst in de lijst staat.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Hint
min met een lambda-functie achter key= geeft de hele deelnemer met de
kleinste tijd, zoals max(players, key=lambda p: p[1]) in het
tweede college. Van die deelnemer geef je
alleen de naam terug. Bij gelijke tijden geeft min vanzelf de eerste.
# jouw oplossing
assert fastest(RESULTS) == "Sem"
assert fastest([["Ali", 20, 600]]) == "Ali"
Stap 5: ranking(results)¶
Geeft een lijst met de namen van alle deelnemers, van de snelste naar de langzaamste. Hebben twee deelnemers dezelfde tijd, dan komt de naam die in het alfabet eerst komt vooraan.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Sem en Lotte hebben allebei 698 seconden. Lotte staat vooraan, want de L komt vóór de S.
Hint
Een sleutel mag ook een lijst zijn. Python vergelijkt twee lijsten zoals twee
woorden: eerst het eerste element, en pas als dat gelijk is het tweede.
[698, "Lotte"] komt dus vóór [698, "Sem"]. Laat de lambda-functie de lijst
[tijd, naam] teruggeven. Zet daarna met een list comprehension alleen de namen
in een lijst.
# jouw oplossing
assert ranking(RESULTS) == ["Lotte", "Sem", "Finn", "Noor", "Yara"]
assert ranking([["Bo", 30, 700], ["Ad", 25, 700]]) == ["Ad", "Bo"]
assert ranking([]) == []
Stap 6: select(results, test)¶
test is een functie die bij een deelnemer True of False teruggeeft. Geeft
een lijst met de deelnemers uit results waarvoor test True teruggeeft, in
dezelfde volgorde.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
De lambda-functie in het eerste voorbeeld geeft True voor wie jonger is dan
18: de jeugd.
Hint
Een list comprehension met een if, zoals in week 2. Roep in de if de functie
test aan op elke deelnemer.
# jouw oplossing
assert select(RESULTS, lambda r: r[1] < 18) == [["Noor", 17, 754], ["Yara", 16, 812]]
assert select(RESULTS, lambda r: r[2] < 700) == [["Sem", 19, 698], ["Lotte", 18, 698]]
assert select(RESULTS, lambda r: r[1] > 30) == []
Stap 7: winner(results, test)¶
Geeft de naam van de snelste deelnemer waarvoor test True teruggeeft. Er is
altijd minstens één zo’n deelnemer.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Hint
Je hebt alles al. winner geeft test mee aan select, en zoekt in wat daar
uitkomt de snelste met fastest. Dat past op één regel.
# jouw oplossing
assert winner(RESULTS, lambda r: r[1] < 18) == "Noor"
assert winner(RESULTS, lambda r: r[1] >= 18) == "Sem"
assert winner(RESULTS, lambda r: r[0][0] == "Y") == "Yara"
Stap 8: een jeugdpodium¶
De schoolrun krijgt een podium voor deelnemers jonger dan een meegegeven
leeftijdsgrens. Schrijf youth_podium(results, age_limit): een lijst met maximaal
drie namen, van snel naar langzaam en bij gelijke tijd op alfabet. Zijn er minder
dan drie geschikte deelnemers, dan is de lijst korter. Zonder geschikte
deelnemers krijg je een lege lijst. De gegevens hebben dezelfde vorm als
RESULTS; namen zijn uniek en leeftijden en tijden zijn gehele getallen.
Wie precies de leeftijdsgrens heeft bereikt, doet niet mee aan dit podium.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Je kent al comprehensions, recursie
en functies als argument.
Als je met zulke middelen zelf de verwerking van invoer naar resultaat ontwerpt,
werk je hier functioneel. Eén eigen functie met een comprehension of recursie
kan al voldoen. Alleen een def rond code met lussen en toekenningen is niet
genoeg. Kies zelf de passende middelen, aanpak en opbouw; bestaande functies
gebruiken mag, maar hoeft niet.
Noteer vóór je programmeert hoe je het podium bepaalt en hoe je de functies opbouwt. Noem daarbij welk functioneel middel je kiest en wat het in jouw verwerking doet. Schrijf daarna je code met een docstring en eigen assertions. Wijs bij de terugblik in je code aan waar je dat middel gebruikt en welk deel van het resultaat het berekent. Vergelijk je uitvoering met je plan: wat heb je behouden of veranderd, en waarom?
Hint
Probeer ook een uitslag waarbij de derde en vierde geschikte deelnemer even snel zijn. Controleer dan welke naam de laatste podiumplaats krijgt.
# jouw plan
# jouw oplossing en eigen assertions
assert youth_podium(RESULTS, 18) == ["Noor", "Yara"]
assert youth_podium(RESULTS, 16) == []
assert youth_podium([], 18) == []
assert youth_podium([["Bo", 17, 700]], 18) == ["Bo"]
assert youth_podium([["Bo", 18, 600], ["Ad", 17, 700]], 18) == ["Ad"]
assert youth_podium(
[["Daan", 17, 700], ["Cato", 16, 700], ["Bo", 17, 600], ["Ad", 15, 500]], 18
) == ["Ad", "Bo", "Cato"]
# vergelijking met je plan
Opdracht 1: dezelfde regel bij gelijke tijden¶
Maak eerst stap 4 tot en met 8 af. Voer de aparte analyseversie hieronder uit, ook als jouw
eigen code anders is. Ze vervangt de gelijknamige functies en RESULTS in je
notebook, maar bevat geen uitwerking van het jeugdpodium.
De school wil voortaan ook bij fastest en winner bij gelijke tijden de
alfabetisch eerste naam als winnaar. Je beschrijft de wijziging; je hoeft haar
niet te programmeren. De voorwaarden voor niet-lege invoer blijven gelden.
RESULTS = [
["Noor", 17, 754],
["Sem", 19, 698],
["Lotte", 18, 698],
["Yara", 16, 812],
["Finn", 21, 745],
]
def fastest(results):
"""Geeft de naam van de deelnemer met de kleinste tijd; results is niet leeg."""
return min(results, key=lambda r: r[2])[0]
assert fastest(RESULTS) == "Sem"
assert fastest([["Ali", 20, 600]]) == "Ali"
def ranking(results):
"""Geeft de namen van snel naar langzaam; bij gelijke tijd op alfabet."""
return [r[0] for r in sorted(results, key=lambda r: [r[2], r[0]])]
assert ranking(RESULTS) == ["Lotte", "Sem", "Finn", "Noor", "Yara"]
assert ranking([["Bo", 30, 700], ["Ad", 25, 700]]) == ["Ad", "Bo"]
assert ranking([]) == []
def select(results, test):
"""Geeft de deelnemers uit results waarvoor test True teruggeeft."""
return [r for r in results if test(r)]
assert select(RESULTS, lambda r: r[1] < 18) == [["Noor", 17, 754], ["Yara", 16, 812]]
assert select(RESULTS, lambda r: r[2] < 700) == [["Sem", 19, 698], ["Lotte", 18, 698]]
assert select(RESULTS, lambda r: r[1] > 30) == []
def winner(results, test):
"""Geeft de naam van de snelste deelnemer waarvoor test True teruggeeft."""
return fastest(select(results, test))
assert winner(RESULTS, lambda r: r[1] < 18) == "Noor"
assert winner(RESULTS, lambda r: r[1] >= 18) == "Sem"
assert winner(RESULTS, lambda r: r[0][0] == "Y") == "Yara"
Beantwoord in de cel hieronder, als commentaar:
Wat is de verantwoordelijkheid van elk van de vier gegeven functies?
Welke functies roepen elkaar aan? Welke functie wordt als argument doorgegeven, en waar wordt die aangeroepen?
Waar moet de regel voor gelijke tijden veranderen? Wijs de sleutel aan en onderbouw waarom deze plek ook het gedrag van
winnerverandert.Wat verandert er voor
fastest,winner,rankingenselectbijRESULTSen bij[["Bo", 16, 700], ["Ad", 17, 700]]? Bespreek bijwinnerzowel jeugd als volwassenen voorRESULTS. Wat gebeurt er zonder gelijke tijden? Welke bestaande assertions moeten veranderen, en welke blijven geldig?
Dit antwoord onderzoekt bestaande samenwerking. Het is afzonderlijk van je ontwerp en code voor het jeugdpodium in stap 8.
# jouw analyse
Tot slot¶
Sem en Lotte liepen even snel: allebei 698 seconden. fastest geeft Sem, omdat
hij eerder in de lijst staat en min bij een gelijke tijd de eerste kiest. De
ranglijst zet Lotte vooraan, omdat daar bij een gelijke tijd het alfabet beslist.
Twee functies, twee regels voor een gelijke stand. Bij de jeugd wint Noor.
In stap 4 tot en met 7 gaf je een functie mee. In stap 4 en 5 gaf je een lambda-functie aan
min en sorted; die riepen die functie bij elke deelnemer aan. In stap 6 schreef je zelf
een functie die een functie als argument krijgt, en in stap 7 gaf je die functie
weer mee.
Zo maakt één winner de winnaar van elke categorie: alleen de lambda-functie die je
meegeeft, verschilt.