COMP10002 Foundations of Algorithms Semester 1, 2021
Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit
COMP10002 Foundations of Algorithms
Semester 1, 2021
Midterm Solutions
Congratulations on completing the mid-semester test! The following document is a guide to our grading. Note that though we include point breakdowns here, this was a guide to our tutors, and every code submission was unique, requiring individual analysis of a submission. Therefore, your grades may not exactly match what you assume you may have received.
However, we are human and make mistakes. If you think we have accidentally awarded you too few points (or too many!) please submit a regrade request. All requests must be made at that link, do not email requests.
Contrary to the initial announcement on the LMS, we are extending the deadline for requests to Friday 23, April at 5PM Melbourne time.
The solutions provided here are modelled off student submissions, intended to illustrate the style that we would expect. While there may be more sophisticated approaches (included some in our internal solutions), these responses illustrated a strong understanding of the problem.
If you think your solution was close, or perhaps even the inspiration for these solutions—well done!
Some of our questions had multiple variants. If the code provided matched the incorrect variant, the rubric assigns a zero to that solution.
1 General Remarks
The MST had questions encompassing a range of difficulties. Question 1 was a good test to make sure you’re meeting the minimum standard for the class, whereas Question 2 was a good challenge question to test if you’ve mastered the material so far, with Question 3 somewhat in the middle.
Given the design of the test, we arranged to add an extra point to all scores. The average before this change was approximately 56% with a standard deviation of 22%.
While the test overall had challenges, it was designed to show students the scope of what they could do with the tools they already had—even if that meant not getting everything right. By comparing your responses with the discussions here, you can understand what types of thinking you were missing, and not just what the exact solutions were.
We were pleased with how everyone fared, and hope it has left you with an opportunity to improve.
Question 1
This question was targeting your understanding of a few concepts:
• Iteration using loops
• Output using printf
• Basic use of variables and C syntax
Most students managed to get a majority of the points available for this question, and write relatively neat and concise code.
There were two variants of this question, requiring slightly different output.
Average score: 3/3
Std. dev: 0.70
Question Text: Variant 1
A k-half-Christmas-tree is represented by 2k lines, each of which has two more stars than the previous line, starting from two, with one letter ‘T’ at the top, and a new line after the tree.
For example, for k=2, the output should be:
T
**
****
******
********
For k=3, the output should be:
T
**
****
******
********
**********
************
...
Solution
1 printf("T\n"); // 0.5 pt
2 int stars = 0; // 0.5pt for all variable declaration and initialisation
3 for (int j = 0; j <= 2 * k; j++) 4 { // 0.5 pt for the outer loop
5 for (int i = 0; i < stars; i++)
6 { // 1 pt for the inner loop, including update of "stars" or 2*i
7 printf("*"); // 0.5 pt for the prints, including "\n" 8 }
9 printf("\n");
10 stars += 2; 11 }
Question Text: Variant 2
A k-half-Christmas-tree is represented by k lines, each of which has two more stars than the previous line, starting from two, with two letter ’L’s at the bottom, and a new line after the tree.
For example, for k=3, the output should be:
**
****
******
LL
For k=4, the output should be:
**
****
******
********
LL
...
Solution
1 int stars = 0; // 0.5pt for all variable declaration and initialisation
2 for (int j = 0; j <= k; j++)
3 { // 0.5 pt for the outer loop
4 for (int i = 0; i < stars; i++)
5 { // 1 pt for the inner loop, including update of "stars"
6 printf("*"); // 0.5 pt for the prints, including "\n" 7 }
8 printf("\n");
9 stars += 2; 10 }
11 printf("LL\n"); // 0.5 pt
Question 2
This question was a riff on isprime, and was designed to test if you could pull together both algorithmic thinking and C programming applied to a multi-stage problem.
The key to solving this problem was to realize that it could be broken down into a series of much simpler steps—this is the process of abstraction we aim to teach in the course.
1. To compute secret_math you need to call secret twice with two different inputs
2. To compute secret and find the i-th k-secret number you need a way to check if a given number is secret, then loop through all the numbers until you find i of them that are secret
3. To check if a number is secret you need to loop through all of its possible divisors and check: (a) If the number is actually a divisor
(b) If the divisor is prime using isprime
(c) If the divisor is less than k
After breaking down the problem like this, it becomes much more manageable and it is possible to realize it requires very few lines of code!
Note that what we call k-secret numbers here in reality are called B-smooth numbers, and have applications in cryp- tography and number theory.
The most common mistakes was failing to break down the problem into smaller steps. This also led to challenges understanding a worded representation of a function with two numerical parameters (i and k).
To do better on a similar problem, a student would be adivsed to go through each task the program needs to complete, and break those into subtasks.
Average score: 1/3
Std. dev: 1.04
Question Text
Given a number N, in cryptography and number theory, we often check if the factors of N that are prime are less than or equal to K. If yes, we will call N a K-secret number.
Note that 1 is always the first K-secret number given any K.
For example, The factors of 11 are 1, 11. Both 1 and 11 are prime, while 11 is not less than or equal to 7. Therefore 11 is not 7-secret.
The factors of 144 are 1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 36, 48, 72, 144. Of these, 2, and 3 are prime. Both 2 and 3 are less than 7, so 144 is 7-secret.
The initial sequence of 7-secret numbers is: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, ...
Write a function
secret_math(int i, int j, int K1, int K2)
that prints out the sum/product (variant 1/variant 2) of the i-th K1-secret number and j-th K2-secret number. You may want to write a supporting function int secret(int i, int K) that returns the i-th K-secret number. Example: secret_math(5, 2, 3, 7)
Should return: 8 Because the 5-th 3-secret number is 6 and the 2nd 7-secret number is 2, and 6+2 = 8.
You may assume that the function int isprime(int n) has been provided and returns 1 if a number is prime and 0 otherwise.
You may also assume that i, j, K1, K2 > 0
Solution
An alternate solution (not depicted) was to save all the k-secret values into an array and pick out the i-th one. While this works, it is inefficient as there is not reason to keep all the smaller k-secret numbers.
1 int secret_math_variant1(int i, int j, int K1, int K2) 2 {
3 return secret(i, K1) * secret(j, K2); // 0.5 point for knowing to use the function ,→ twice with the right operator in between
4 }
5
6 int secret_math_variant2(int i, int j, int K1, int K2) 7 {
8 return secret(i, K1) + secret(j, K2); // 0.5 point for knowing to use the function ,→ twice with the right operator in between
9 }
10
11 int secret(int i, int K) 12 {
13 int count = 0;
14 for (int num = 1;; num++) 15 {
16 if (is_number_k_secret(num, K)) 17 {
18 // 1 point for having a loop that breaks after finding the i-th K-secret number 19 count++;
20 if (count == i)
21 return num;
22 }
23 }
24 }
25
26 // the loop below must loop to <= num else it might miss num > K if num is prime.
27 // -1.5 if the below is missing in its entirety or is largely incorrect
28 int is_number_k_secret(int num, int K) 29 {
30 int any_prime_factors_above_K = 0;
31 for (int divisor = 1; divisor <= num; divisor++) 32 { // 0.5 for having the for loop over the divisors
33 if (num % divisor == 0) 34 {
35 if (is_prime(divisor) && divisor > K)
36 { // 0.5 points for checking is_prime, 0.5 points for divisor > K
37 return 0; 38 }
39 }
40 return 1; 41 }
42 }
Question 3
This question was meant to be a chance to demonstrate an understanding of the basics of accessing and setting array elements. It also tested if a student understood that a char in C holds an underlying numerical value, and that the two
are interchangeable. Thus including numerical values in the array was a minor trap for the unwary. One of the most common errors was failing to do the swap requested in the question.
A stylistic oddity we saw among a few submission was the failure to use all three conditionals in a single combined statement (as below). Doing the check in one line would here not be inappropriate.
Average score: Std. dev:
Solution
1.24/3
1.14
1 int find_bby(char rooms[], int n) 2 {
3 int door_index = -1;
4 int bby_index = -1;
5 for (int i = 0; i < (n - 2); i++) // 0.5 points for loop 6 {
7 if (rooms[i] == 3 && rooms[i + 1] == 8 && rooms[i + 2] == 3) 8 { // 0.5 points for finding 383 (numeric)
9 door_index = i;
10 }
11
12 if (rooms[i] == 'b' && rooms[i + 1] == 'b' && rooms[i + 2] == 'y') 13 { // 0.5 points for finding bby
14 bby_index = i; 15 }
16 }
17
18 // validate
19 if (door_index == -1 || bby_index == -1) 20 {
21 return -1; // 0.5 correct return condition (need both this and the one below) 22 }
23
24 // swap // 1pt correct swap
25 rooms[door_index] = 'b' ;
26 rooms[door_index + 1] = 'b' ;
27 rooms[door_index + 2] = 'y' ;
28
29 rooms[bby_index] = 3;
30 rooms[bby_index + 1] = 8;
31 rooms[bby_index + 2] = 3;
32 return 1; // 0.5 correct return condition (need both this and the one above) 33 }
Question 4
The true/false questions were designed to test basic conceptual understandings and were in general handled well by students.
Short descriptions of the answers and distractors follows.
• C is an imperative programming language—meaning that the language uses sequences of statements that change a programs state. This was discussed in the intro to C.
• While big-O notation describes the asymptotic complexity of an algorithm, it doesn’t actually tell you how long a specific instance of a problem will take to solve
• An algorithm’s runtime is not the same as it’s big-O complexity but the two are connected. For a non specific bigger input, the complexity class tells how how to expect the algorithm’s runtime will grow.
• Casting a variable in C lets you use a variable as-if it were of a different type, but does not actually change the underlying type of the variable.
Average score: 1/1
Std. dev: 0.43
Variant 1
Choose the answer that is false.
• Casting a variable can permanently change the type of the variable
• C is an imperative programming language
• An ordinary personal computer can solve some problems that have algorithmic complexity O(2n) where n is the input size
• An algorithm’s actual run time is correlated to the algorithmic complexity of its code in machine-language
Variant 2
Choose the answer that is true.
• An algorithm’s actual run time is correlated to the algorithmic complexity of its code in machine-language
• C is a functional programming language
• An ordinary personal computer cannot not solve any problem that has algorithmic complexity O(2n) where n is the input size
• Casting a variable can permanently change the type of the variable
2022-03-30