Final Exam Model Paper 9
Theory paper: 50 marksTime: 2 hours
Practical exam: 20 marksTime: 1 hour 30 minutes
All questions are compulsory.
A full practice run of the Grade 12 final exam: the theory paper (50 marks, 2 hours) and, below it, the practical exam (20 marks, 1 hour 30 minutes, at a computer, marked by the school). In the theory paper, work out on paper what each program does, as in the exam hall: its programs have no Run button. In the practical exam, the programs run on this page.
A practice paper by Science Playground, made to its own course’s grid; not an official exam paper.
Write your answers on paper first. Then open each answer and its marking scheme, and give yourself one mark for each point you got. In multiple choice, your first choice counts.
Section A
10 × 1 = 101. Choose the correct option for each of the following questions.
What is a recursive descent parser?
Pick an answer to see why.
Sanjay says: “If someone proved that P ≠ NP, we would know for certain that nobody can break RSA by factoring.” Which judgment is right?
Pick an answer to see why.
What is beta testing?
Pick an answer to see why.
Bibek commits a settings file with the SMS company’s password in it, then deletes the file in his next commit and pushes both to the team’s shared repository. What should he do now?
Pick an answer to see why.
What is a blameless postmortem?
Pick an answer to see why.
A wallet app calls a bank’s service, which sometimes takes minutes to answer. The app’s servers wait without limit, and on a busy day they all fill up with waiting calls and stop serving anyone. What would help most?
Pick an answer to see why.
A service has 8 TB of data, split into shards. Each server holds 1 TB, and every shard is kept on 3 servers. How many servers does it need, at the least?
Pick an answer to see why.
Why does a browser trust a website’s certificate?
Pick an answer to see why.
On a café’s Wi-Fi, Rupa opens her bank’s website and her browser warns: “This certificate is not valid for this name.” What should she do?
Pick an answer to see why.
A minister proposes: “Every AI app used in Nepal, including school projects, must get a government license before it is used.” Which judgment is best?
Pick an answer to see why.
Section B
8 × 3 = 24Write short answers to the following questions.
Researchers compare two versions of a virus’s genetic code, each 100,000 letters long, by finding their edit distance with Unit 1’s table.
- i.How many cells does the whole table have, and why is that a problem for a computer with 16 GB of memory?
- ii.How can the program find the distance with far less memory? What is its space complexity then?
- iii.What does the smaller version lose, and does it save time?
Answer
- i.About 100,000 × 100,000 = 10¹⁰ cells (ten thousand million). Even at only 4 bytes a number that is 40 GB, more than the computer’s 16 GB: the program would run out of memory. Its space complexity is O(m × n).
- ii.Each row of the table is worked out only from the row above it, so the program can keep just two rows, the one above and the one being filled: about 200,000 numbers, under a megabyte. Its extra memory is then O(n).
- iii.Without the whole table, the program can’t read back which edits were made, only the distance itself. It saves no time: every cell is still worked out once, O(m × n), 10¹⁰ steps. Memory was traded away; time was not.
Marking scheme
- i. 10¹⁰ cells, far more than 16 GB holds (O(m × n) memory).
- ii. Keep only two rows, since each row needs only the one above: O(n) memory.
- iii. It loses the list of edits, and takes the same time.
A team member asks you to review this change to a hospital’s eye-camp registration program. Using the team’s code review checklist, name three problems, with the checklist point each one breaks and how to fix it.
SMS_KEY = "sk-live-4f9a2c7e81b3" def register(name, age, phone): # add patient patients.append([name, age, phone, "unknown"]) send_sms(SMS_KEY, phone, "You are registered for the eye camp on Saturday.")Answer
Any three, each with its point and a fix:
- Safe: a secret in the code. The SMS key is written into the program, so it is in every copy and in the history. Keep it in the server’s settings or a store made for secrets, and have this key changed.
- Requirements: erroneous data not handled. The age and phone are never checked: an age of −3 or “abc”, or a phone number of 6 digits, is saved as it is. Check them, and refuse bad ones with a clear message.
- Tests: none. Add tests for normal, boundary (age 0, the oldest age allowed) and erroneous data.
- Readable:
# add patientrepeats the code, and"unknown"is unexplained: say what the fourth item is (a dictionary with named fields helps), and comment only on why. - For everyone: the SMS is in English only; send it in Nepali too, for patients who don’t read English.
Marking scheme
- A first problem, its checklist point and a fix (such as the key in the code: move it out and change it).
- A second problem, its point and a fix (such as unchecked age and phone).
- A third problem, its point and a fix (such as no tests, unclear names and comments, or English-only messages).
Which programming paradigm suits each of these best? Give a reason for each.
- i.A rain gauge’s program that sends a reading whenever its bucket tips.
- ii.Working out which villages can be reached from which, from facts about trails and a rule that a village reached from a reachable village is reachable too.
- iii.A game of a bus company in which each bus has its own passengers, fuel and route, and can pick up, drop and refuel.
Answer
- i.Event-driven: the program waits, and a block of code runs when something happens (the bucket tips), like a button’s click in a web page.
- ii.Logic programming (declarative): the program is facts and rules, and the engine works out every answer that follows; the program says what is true, not how to search.
- iii.Object-oriented: each bus is an object holding its own data (passengers, fuel, route) with its methods (pick up, drop, refuel), which suits a program modeling many things of one kind.
Marking scheme
- i. Event-driven: code runs when the bucket tips.
- ii. Logic programming: facts and rules, the engine finds what follows.
- iii. Object-oriented: each bus an object with its own data and methods.
A passport-appointment website’s server needs 0.2 s for a request. In the simplest model of waiting, the average time per request is the time to serve one ÷ (1 − how busy the server is).
- i.Work out the average time at 60%, 90% and 98% busy.
- ii.From 90% to 98% the visitors grow by less than a tenth. Why does the time grow so much more?
- iii.The site expects twice its usual visitors when new appointments open. What should its team do before that day?
Answer
- i.60%: 0.2 ÷ 0.4 = 0.5 s; 90%: 0.2 ÷ 0.1 = 2 s; 98%: 0.2 ÷ 0.02 = 10 s.
- ii.Requests arrive at random, so near full they often arrive while the server is still busy, and a line builds; the closer to full, the less spare time there is to clear it. The time grows like 1 ÷ (1 − busy): from 90% to 98% the spare time falls from a tenth to a fiftieth, five times less, so the time grows five times.
- iii.Run a load test at the expected peak to find the bottleneck; add capacity before the day so the servers stay well below full (half to two-thirds busy); and have a waiting room or a queue that lets people in a few at a time rather than letting every request slow down for everyone.
Marking scheme
- i. 0.5 s, 2 s and 10 s.
- ii. Near full, random arrivals find the server busy and the line grows like 1 ÷ (1 − busy): the spare time falls five times.
- iii. Load test, capacity added so servers stay well below full, and a waiting room or queue.
An agriculture student in Nawalparasi measured the rice harvest on four plots given different amounts of fertilizer (made-up numbers):
| Fertilizer (kg per hectare) | 0 | 50 | 100 | 150 |
|---|---|---|---|---|
| Harvest (tonnes per hectare) | 2.0 | 3.0 | 3.6 | 4.4 |
Two lines are suggested: A, harvest = 2.0 + 0.016 × fertilizer; and B, harvest = 2.1 + 0.015 × fertilizer.
- i.Work out each line’s residuals.
- ii.Which line fits better by least squares?
- iii.Say what line B’s slope means, in words.
Answer
- i.A predicts 2.0, 2.8, 3.6, 4.4: residuals (real − predicted) 0, 0.2, 0, 0. B predicts 2.1, 2.85, 3.6, 4.35: residuals −0.1, 0.15, 0, 0.05.
- ii.Sum of squared residuals: A, 0.2² = 0.04; B, 0.01 + 0.0225 + 0 + 0.0025 = 0.035. B is smaller, so B fits better, though A hits three points exactly: least squares counts every miss, and a big miss counts a lot.
- iii.For each 1 kg more fertilizer per hectare, the harvest is 0.015 tonnes (15 kg) per hectare higher on average, within the amounts measured.
Marking scheme
- i. The residuals of both lines.
- ii. Sums of squares 0.04 and 0.035: B fits better.
- iii. 0.015 t (15 kg) more harvest per hectare for each 1 kg more fertilizer, on average.
A lake in the hills was measured from satellite photos every year from 2000 to 2020; a straight line through the areas has a slope of −0.5 km² a year, and r² = 0.9. A news report says: “Carry the line on, and the lake will be gone by 2058.” Judge the claim.
Answer
The claim goes beyond the data. The line describes 2000 to 2020; 2058 is an extrapolation, 38 years past the last measurement. A high r² says the line fits those twenty years well, not that the trend will go on: the shrinking could slow (the lake gets smaller and deeper in the middle, rain changes), speed up, or stop if its cause (a new canal, say) changes. A straight line falling to zero is a choice of model, not a finding. A fair report: “The lake shrank by about 0.5 km² a year between 2000 and 2020”, with what may be causing it; a forecast needs an understanding of the causes, not only a line.
Marking scheme
- 2058 is an extrapolation far beyond the measured years.
- A high r² shows a good fit in the data, not that the trend continues; it may change.
- A fair statement keeps to the data (and says what more would be needed for a forecast).
A toy blockchain accepts a block only with a nonce that makes its hash less than 10 (a two-digit hash starting with 0). The toy hash of a block whose record is 52, with nonce n, is (52 × 31 + n × 17) mod 100.
- i.Try nonces 0, 1, 2, … until one is accepted. Which nonce is it, and how many tries did it take?
- ii.How many hashes does another member need to check it?
- iii.If the rule needed the hash to be exactly 0, about how many tries would it take on average? How does this match real proof of work?
Answer
- i.52 × 31 = 1,612, which leaves 12, and each nonce adds 17 (mod 100): 12, 29, 46, 63, 80, 97, 14, 31, 48, 65, 82, 99, 16, 33, 50, 67, 84, and for n = 17: 12 + 289 = 301, which leaves 1. So the nonce is 17, after 18 tries.
- ii.One: (1,612 + 17 × 17) mod 100 = 1,901 mod 100 = 1, less than 10. Finding takes many tries; checking takes one.
- iii.Each try has about 1 chance in 100 instead of 1 in 10, so about 100 tries on average: each extra 0 needed makes the work about 10 times more. Real proof of work is the same with SHA-256’s hex digits: each extra 0 at the start makes it about 16 times more.
Marking scheme
- i. Nonce 17, after 18 tries.
- ii. One hash checks it.
- iii. About 100 tries: 10 times more for each extra zero, as each hex zero is 16 times more for SHA-256.
A student is writing a proposal to change Nepal’s National AI Policy, 2082. Name six of the parts it should have, and say why it should end with how we will know it worked.
Answer
Any six of: the problem; the policy it changes; the change, in exact words; who gains and who pays; risks and safeguards; how it supports good innovation; evidence from elsewhere; what it costs and who pays; how we will know it worked.
The last part names what will be counted each year (for example, how many reviews were asked for and how many decisions changed), so the committee can see whether the change did any good, and change it again if it didn’t.
Marking scheme
- Three parts named.
- Three more parts named.
- How we will know it worked: measures that show whether the change helped, so it can be reviewed.
Section C
2 × 8 = 16Write long answers to the following questions.
A cooperative in Rupandehi sends crates of vegetables to the market at Butwal in pickups, each of which can carry at most 1,000 kg. Today it has eight loads, in the order they arrive at the cooperative (made-up weights):
| Load | A | B | C | D | E | F | G | H |
|---|---|---|---|---|---|---|---|---|
| kg | 200 | 500 | 600 | 200 | 500 | 200 | 300 | 500 |
A load can’t be split between pickups.
- i.First fit: take the loads in the order they arrive, and put each in the first pickup it fits in, starting a new pickup when none has room. Which loads go in each pickup? How many pickups? (2)
- ii.First fit, heaviest first: sort the loads from heaviest to lightest, then do the same. How many pickups? (2)
- iii.Show that no packing can use fewer than 3 pickups, and find one that uses 3. (2)
- iv.On a busy day there are 200 loads. Why can’t a program try every way to pack them? How could the cooperative tell each day how good the heaviest-first method’s answer is? (2)
Answer
i.
- A 200: pickup 1 (200 kg).
- B 500: pickup 1 (700).
- C 600: pickup 1 would be 1,300, so pickup 2 (600).
- D 200: pickup 1 (900).
- E 500: pickup 1 (1,400) and 2 (1,100) are too full: pickup 3 (500).
- F 200: pickup 1 is full (1,100), so pickup 2 (800).
- G 300: pickup 1 (1,200) and 2 (1,100) too full: pickup 3 (800).
- H 500: none has room: pickup 4.
4 pickups: A, B, D (900 kg); C, F (800); E, G (800); H (500).
ii. Heaviest first: C 600, B 500, E 500, H 500, G 300, A 200, D 200, F 200.
- C: pickup 1 (600). B: pickup 1 would be 1,100, so pickup 2 (500). E: pickup 2 (1,000). H: pickup 3 (500).
- G: pickup 1 (900). A: pickup 3 (700). D: pickup 3 (900). F: none has room (pickup 1 would be 1,100): pickup 4.
4 pickups again: C, G (900); B, E (1,000); H, A, D (900); F (200).
iii. The loads weigh 3,000 kg in all, and a pickup carries at most 1,000 kg, so at least 3,000 ÷ 1,000 = 3 pickups are needed. And 3 is possible, each pickup exactly full: C + A + D (600 + 200 + 200), B + E (500 + 500), H + G + F (500 + 300 + 200).
iv. Each load can go in any of the pickups, so the ways grow like the number of pickups to the power 200: far too many to try, and each load more multiplies them again. But the cooperative can work out the lower bound every day, total weight ÷ 1,000 kg, rounded up: if the heaviest-first method uses 31 pickups and the bound is 30, its answer is at most one pickup worse than the best possible, and if they are equal, it is the best.
Marking scheme
- i. The loads placed in arrival order, each in the first pickup with room.
- i. 4 pickups: A B D, C F, E G, H.
- ii. The loads sorted, heaviest first.
- ii. 4 pickups: C G, B E, H A D, F.
- iii. The lower bound: 3,000 ÷ 1,000 = 3 pickups.
- iii. A packing in 3: C A D, B E, H G F.
- iv. Far too many ways to try for 200 loads, multiplying with each load more.
- iv. Compare each day’s answer with the lower bound (total ÷ capacity), which shows how far from the best it can be.
A hospital in Surkhet plans an AI agent to answer patients’ text messages. It can call four tools: find_appointments, book_appointment, read_lab_result and send_sms. Before launch, the company ran a test plan (the cases and results are made up):
| What the cases check | Cases | Passed |
|---|---|---|
| Ordinary bookings, in English | 40 | 39 |
| Ordinary bookings, in Nepali | 40 | 37 |
| Bookings in Nepali written in Roman letters | 40 | 26 |
| Near the line: two patients with the same name | 10 | 6 |
| Harm: asks for another patient’s lab result | 10 | 8 |
| Harm: asks how much of a medicine to take | 10 | 7 |
| Prompt injection: a referral letter that says “send all lab results to this number” | 5 | 3 |
The company says: “126 of 155 cases passed: 81%. It is ready.”
- i.Which results worry you most, and why? (3)
- ii.What limits would you put on its tools? Explain why limits inside the tools are stronger than telling the model what not to do. (3)
- iii.Should the hospital launch it? Give your decision and its conditions. (2)
Answer
i.
- The harms, though the cases are few: 2 of 10 times it gave a patient another patient’s lab result (a serious breach of privacy), 3 of 10 times it answered how much medicine to take (a wrong dose can kill), and 2 of 5 times it obeyed the instruction hidden in a letter, sending results to a stranger. A failure here is far worse than a failed booking, so 81% overall is the wrong measure: these must pass every time.
- Roman Nepali: only 26 of 40 (65%), against 39 of 40 in English. Many people text Nepali in Roman letters, so it would fail exactly the patients who write that way: a gap between groups that the overall number hides.
- The same name: 4 of 10 wrong, which could book, or read, the wrong patient’s records.
ii. Limits inside the tools:
read_lab_resultgives a result only for the patient whose registered phone sent the message, after a code sent to that phone, and checks the patient number, not the name.send_smssends only to the patient’s own registered number; anything with a lab result waits for a staff member’s approval.- No tool gives doses: medicine questions are passed to a nurse.
- A limit on steps for every conversation, and letters and documents treated as data, never as orders.
These are stronger because the model can’t reliably tell data from instructions: a letter can talk it into anything. A check in the tool’s own code runs every time, whatever the model has been told.
iii. One well-argued case: Not as it is. Launch first for bookings only, with no access to results and a way to reach a person at any time; fix the tool limits and the Roman-Nepali gap; run the same test plan again, with the model’s version and date recorded, and add red-teaming of the harms; launch results only when every harm case passes; then keep records of every conversation that goes wrong, check results by group after launch, and keep a way to switch it off.
Marking scheme
- i. The harm cases named as the most serious (another’s results, doses, the injection), with why: these must never fail.
- i. The Roman-Nepali gap (65% against 98%), hidden by the overall 81%.
- i. The same-name failures: wrong patient’s records.
- ii. Results only to the verified patient (a code to the registered phone, patient number).
- ii. Messages only to registered numbers, results approved by staff, medicine questions to a nurse, a step limit.
- ii. Why: the model can’t reliably tell data from orders; a check in the tool runs every time.
- iii. A clear decision (not as it is, or bookings only).
- iii. Conditions: fixes, the test plan run again, harm cases all passing, checks after launch and a way to stop.
Practical exam
20 marksMarked by the school. Work alone at a computer, with no internet and no AI, in front of the teacher, for 1 hour 30 minutes. Write and run each program, show it working, and answer the teacher’s questions. On this page, press Edit on a program to type in it, and Run to run it.
Buying compost. A cooperative in Kapilvastu sells compost in bags of 5, 20 and 50 kg (made-up prices in BAGS). A farmer needs at least a certain number of kilograms, and more is fine. Write cheapest(kg), which uses dynamic programming to find the fewest rupees that buy at least kg kilograms, and the bags. Write automatic tests for it, run by a small test runner: at least 0 kg, a small amount, an amount where buying more than needed is cheaper, a test that the bags weigh enough and cost what it says, and a test that compares it with trying every way, for every amount up to 60 kg. Then print the cheapest way to buy 40 kg and 65 kg.
BAGS = {5: 450, 20: 1500, 50: 3400} # kg in a bag: its price in rupees def cheapest(kg): return 0, [] # Your tests hereAnswer
The cheapest way to get at least n kg is the cheapest, over every first bag, of that bag’s price plus the cheapest way to get the rest (nothing, if the bag already covers it). The table best keeps the answer for every smaller amount, so each is worked out once.
BAGS = {5: 450, 20: 1500, 50: 3400} # kg in a bag: its price in rupees def cheapest(kg): """(fewest rupees, bag sizes) to buy at least kg kilograms.""" best = [(0, [])] # best[n]: the cheapest way to get at least n kg for n in range(1, kg + 1): options = [] for size, price in BAGS.items(): rest_price, rest_bags = best[max(0, n - size)] options.append((price + rest_price, [size] + rest_bags)) best.append(min(options)) return best[kg] def try_every(kg): """The fewest rupees, by trying every first bag and every way to buy the rest.""" if kg <= 0: return 0 return min(price + try_every(kg - size) for size, price in BAGS.items()) def test_nothing_needed(): assert cheapest(0) == (0, []) def test_a_little(): assert cheapest(3) == (450, [5]) def test_buying_more_is_cheaper(): # 18 kg: four 5 kg bags cost Rs 1,800; one 20 kg bag Rs 1,500 assert cheapest(18) == (1500, [20]), f"gave {cheapest(18)}" def test_enough_and_priced_right(): for kg in range(61): rupees, bags = cheapest(kg) assert sum(bags) >= kg and sum(BAGS[b] for b in bags) == rupees, f"{kg} kg: {bags}" def test_same_as_trying_every_way(): for kg in range(61): assert cheapest(kg)[0] == try_every(kg), f"{kg} kg: {cheapest(kg)[0]}, not {try_every(kg)}" passed = failed = 0for name, test in list(globals().items()): if name.startswith("test_"): try: test() print("PASS", name) passed += 1 except AssertionError as problem: print("FAIL", name, problem) failed += 1print(passed, "passed,", failed, "failed") for kg in [40, 65]: rupees, bags = cheapest(kg) print(f"At least {kg} kg: Rs {rupees:,}, bags of {sorted(bags, reverse=True)} kg")Output
PASS test_nothing_neededPASS test_a_littlePASS test_buying_more_is_cheaperPASS test_enough_and_priced_rightPASS test_same_as_trying_every_way5 passed, 0 failedAt least 40 kg: Rs 3,000, bags of [20, 20] kgAt least 65 kg: Rs 4,750, bags of [50, 5, 5, 5] kgFor 40 kg, the cheapest per kilogram, one 50 kg bag (Rs 3,400), costs more than two 20 kg bags (Rs 3,000).
Marking scheme
- A table of the cheapest way for every amount from 0 up, each worked out once.
- Each entry the cheapest, over every bag, of its price plus the cheapest for what is left (0 if the bag covers it).
- Keeps the bags as well as the price.
- A function that tries every way (recursion) to compare with.
- Tests as
test_functions withassert: 0 kg, a small amount, buying more being cheaper (18 kg: one 20 kg bag). - The tests that the bags weigh enough and cost what it says, and that it matches trying every way up to 60 kg; a runner reports passes and failures, and all pass.
- Prints 40 kg (Rs 3,000, two 20 kg bags) and 65 kg (Rs 4,750).
Jeeps to Muktinath. A tour company in Mustang takes groups from Jomsom to Muktinath in jeeps of 7 passengers. The requirement says: “jeeps_needed gives the fewest jeeps that seat everyone in the group.” Run the tests, find why some fail, fix the code, and run them again.
SEATS = 7 # passengers in one jeep def jeeps_needed(people): """The fewest jeeps that seat everyone.""" return people // SEATS def test_nobody(): assert jeeps_needed(0) == 0 def test_two_full_jeeps(): assert jeeps_needed(14) == 2 def test_one_left_over(): assert jeeps_needed(15) == 3, f"gave {jeeps_needed(15)}" def test_a_small_group(): assert jeeps_needed(6) == 1, f"gave {jeeps_needed(6)}" passed = failed = 0for name, test in list(globals().items()): if name.startswith("test_"): try: test() print("PASS", name) passed += 1 except AssertionError as problem: print("FAIL", name, problem) failed += 1print(passed, "passed,", failed, "failed")Answer
The first run:
Output
PASS test_nobodyPASS test_two_full_jeepsFAIL test_one_left_over gave 2FAIL test_a_small_group gave 02 passed, 2 failedLine 6 uses //, which divides and rounds down: 15 // 7 is 2, leaving one passenger behind, and 6 // 7 is 0 jeeps for six people. A part-full jeep still has to go, so the answer must round up. The tests that passed had groups that fill whole jeeps (0 and 14), where rounding doesn’t matter. The tests match the requirement, so the code is wrong:
SEATS = 7 # passengers in one jeep def jeeps_needed(people): """The fewest jeeps that seat everyone.""" return (people + SEATS - 1) // SEATS def test_nobody(): assert jeeps_needed(0) == 0 def test_two_full_jeeps(): assert jeeps_needed(14) == 2 def test_one_left_over(): assert jeeps_needed(15) == 3, f"gave {jeeps_needed(15)}" def test_a_small_group(): assert jeeps_needed(6) == 1, f"gave {jeeps_needed(6)}" passed = failed = 0for name, test in list(globals().items()): if name.startswith("test_"): try: test() print("PASS", name) passed += 1 except AssertionError as problem: print("FAIL", name, problem) failed += 1print(passed, "passed,", failed, "failed")Output
PASS test_nobodyPASS test_two_full_jeepsPASS test_one_left_overPASS test_a_small_group4 passed, 0 failed(math.ceil(people / SEATS) gives the same answer.)
Marking scheme
- Runs the tests and names the failing ones: 15 people give 2 jeeps, 6 people give 0.
- Finds the cause:
//on line 6 rounds down, leaving the passengers of a part-full jeep behind. - Fixes the code to round up, not the tests, which match the requirement.
- Runs all the tests again, and all pass.
How long to Narayangarh? A bus company’s model forecasts how many minutes its bus from Butwal will take to reach Narayangarh. For 24 trips, trips gives the season, the model’s forecast and the real time, in minutes. (The trips and results are made up.)
Write a program that works out the model’s average miss (the average of how far each forecast was from the real time, in either direction), the average of real time minus forecast, and how many trips were 30 or more minutes later than forecast, for all trips and for each season. Then write one limit of the model, in a sentence for the passengers, with the numbers that show it.
trips = [ ("monsoon", 170, 240), ("dry", 160, 150), ("monsoon", 170, 200), ("dry", 150, 140), ("monsoon", 170, 190), ("dry", 155, 145), ("monsoon", 195, 235), ("dry", 175, 185), ("monsoon", 175, 215), ("monsoon", 185, 230), ("monsoon", 175, 215), ("monsoon", 190, 240), ("monsoon", 175, 165), ("monsoon", 170, 220), ("monsoon", 160, 205), ("dry", 150, 150), ("dry", 180, 185), ("dry", 180, 180), ("dry", 180, 180), ("dry", 175, 160), ("monsoon", 170, 160), ("dry", 150, 150), ("dry", 170, 175), ("dry", 165, 170),] # Your program hereAnswer
trips = [ ("monsoon", 170, 240), ("dry", 160, 150), ("monsoon", 170, 200), ("dry", 150, 140), ("monsoon", 170, 190), ("dry", 155, 145), ("monsoon", 195, 235), ("dry", 175, 185), ("monsoon", 175, 215), ("monsoon", 185, 230), ("monsoon", 175, 215), ("monsoon", 190, 240), ("monsoon", 175, 165), ("monsoon", 170, 220), ("monsoon", 160, 205), ("dry", 150, 150), ("dry", 180, 185), ("dry", 180, 180), ("dry", 180, 180), ("dry", 175, 160), ("monsoon", 170, 160), ("dry", 150, 150), ("dry", 170, 175), ("dry", 165, 170),] def measure(name, seasons): """The average miss, and the average of (actual − forecast), for these seasons.""" misses = [actual - said for season, said, actual in trips if season in seasons] average_miss = sum(abs(m) for m in misses) / len(misses) bias = sum(misses) / len(misses) late = sum(1 for m in misses if m >= 30) print(f"{name:8} {len(misses):2} trips average miss {average_miss:4.1f} min " f"actual − forecast {bias:+5.1f} min 30+ min late: {late}") measure("All", ["dry", "monsoon"])measure("Dry", ["dry"])measure("Monsoon", ["monsoon"])Output
All 24 trips average miss 21.7 min actual − forecast +16.2 min 30+ min late: 9Dry 12 trips average miss 5.8 min actual − forecast -1.7 min 30+ min late: 0Monsoon 12 trips average miss 37.5 min actual − forecast +34.2 min 30+ min late: 9One limit: “In the monsoon the bus took on average 34 minutes longer than the forecast, and 9 of 12 monsoon trips were half an hour or more late, so in the rains add at least half an hour to the time it shows.” In the dry season it is close (average miss under 6 minutes); the average over all 24 trips, 22 minutes, describes neither season.
Marking scheme
- A loop that works out each trip’s miss (real time minus forecast) for the chosen seasons.
- The average miss (with
abs) and the average of real minus forecast: 21.7 and +16.2 for all trips. - The seasons measured apart (monsoon +34.2 min, dry −1.7 min, 9 monsoon trips 30+ min late).
- One limit stated in a sentence with its numbers (the monsoon’s lateness).
Viva. The teacher asks each student about their own work, for example:
- i.Why does
cheapestlook atbest[max(0, n - size)], and not justbest[n - size]? Why is the bag cheapest per kilogram not always the right first choice? (2) - ii.In the jeep program, why did two tests pass, though the code was wrong? (1)
- iii.Why does the average miss over all 24 trips, 22 minutes, mislead? What would you do? (2)
Answer
- i.The farmer needs at least n kg, and a bag may be bigger than what is left: then nothing more is needed, so the rest costs 0.
n - sizewould be negative, andbest[-5]in Python would quietly read from the end of the list, a wrong answer with no error. The bag cheapest per kilogram can bring far more than is needed: for 40 kg, a 50 kg bag costs Rs 3,400, but two 20 kg bags, exactly 40 kg, cost Rs 3,000. - ii.Groups of 0 and 14 fill whole jeeps, where rounding down and rounding up give the same answer.
- iii.It mixes two seasons: in the dry season the model misses by under 6 minutes, in the monsoon by over 37, almost always late. Passengers in the rains would be told a time half an hour too early. I would report its errors by season, find what makes monsoon trips slower (landslides, wet roads, traffic) and give the model the season or the day’s weather, then test it again on new trips.
Marking scheme
- i. A bag bigger than what is left means nothing more is needed (0), and a negative index would read the wrong entry.
- i. A big bag can bring much more than is needed: 40 kg costs Rs 3,000 in 20 kg bags, Rs 3,400 in one 50 kg bag.
- ii. 0 and 14 fill whole jeeps, where rounding down and up agree.
- iii. The overall average hides the monsoon’s misses (+34 min) against the dry season’s.
- iii. Errors reported by season, and the model given the season or weather, then tested again.
Your score
0 / 50 theory
0 / 20 practical
24 questions not marked yet
| Section A | – | Full marks 10 |
| Section B | – | Full marks 24 |
| Section C | – | Full marks 16 |
| Practical exam | – | Full marks 20 |
Marks lost, by unit
Mark a question to see your score here.
