CS302 Midterm, Fall, 2014
James S. Plank
Answers and Grading
Question 1: 14 points
- A: Straight from the lecture notes - O(m log(m)) - n.
You get .20 points for l, m or o.
- B: Each deletion is O(log(n)) so this one is O(m log(n)).
One point for m, .25 for l, n or o.
- C: Each Find() is O(α(n)) so this one is O(m α(n)).
One point for i, .5 for j, .2 for
h, k or f.
- D: Traversing the map is linear as is creating the vector:
O(m) - f. You get 0.2 for g.
- E: Traversing the vector is linear, as is creating the heap:
O(m) - f. You get 0.2 for g.
- F: Each Find() is O(log(n)) so this one is O(m log(n)).
One point for m, .25 for l, n or o.
- G: There are exactly m! of these permuations: x
You get .2 points for w.
- H: Each Pop() is O(log(n)) so this one is O(m log(n)).
One point for m, .25 for l, n or o.
- I: This is like enumerating all m-digit numbers in base n: s.
You get .5 points for u.
- J: This is O(m log(m)), but if you put O(m2), I gave you
full credit. (n and r).
- K: Each Push() is O(log(n)) so this one is O(m log(n)).
One point for m, .25 for l, n or o.
- L: Straight from the lecture notes - O(m2) - r.
You get .25 points for q.
- M: O(m log(m)), plain and simple - n.
You get .20 points for l, m or o.
- N: Each Union() is O(1)), so this is O(m)) - f.
You get .20 points for i or j.
This is an interesting example of crowd-sourcing: The class majority got 100%:
| a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z |
A | 1 | 0 | 0 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | 2 | 56 | 3 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
B | 0 | 0 | 0 | 7 | 2 | 4 | 0 | 0 | 0 | 0 | 0 | 3 | 54 | 2 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
C | 0 | 2 | 5 | 1 | 1 | 1 | 1 | 0 | 44 | 1 | 1 | 0 | 14 | 2 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
D | 1 | 0 | 1 | 1 | 2 | 37 | 4 | 0 | 0 | 0 | 0 | 2 | 18 | 3 | 0 | 3 | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
E | 0 | 1 | 0 | 0 | 4 | 48 | 8 | 0 | 0 | 0 | 0 | 0 | 3 | 8 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
F | 0 | 0 | 1 | 1 | 0 | 3 | 0 | 0 | 3 | 0 | 0 | 1 | 60 | 2 | 1 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
G | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 2 | 1 | 6 | 7 | 9 | 1 | 0 | 1 | 37 | 8 | 0 |
H | 0 | 0 | 0 | 8 | 1 | 3 | 0 | 0 | 1 | 0 | 0 | 1 | 58 | 1 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
I | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 2 | 1 | 37 | 23 | 0 | 0 | 3 | 1 | 4 | 1 |
J | 0 | 1 | 0 | 0 | 12 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 54 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
K | 0 | 0 | 0 | 5 | 1 | 3 | 1 | 0 | 1 | 0 | 2 | 1 | 59 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
L | 0 | 0 | 0 | 0 | 2 | 4 | 0 | 0 | 0 | 0 | 1 | 5 | 0 | 2 | 1 | 0 | 3 | 57 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
M | 0 | 1 | 0 | 0 | 11 | 13 | 0 | 0 | 0 | 0 | 0 | 4 | 8 | 30 | 1 | 5 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
N | 24 | 0 | 0 | 0 | 0 | 41 | 0 | 0 | 4 | 0 | 0 | 0 | 3 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Question 2: 17 points
- A - D: Each of these returns the root of the set: 6, 10, 10 and 4.
1 point each.
- E: The set rooted by 10 is bigger, so 10 becomes the parent of 6:
Grading. I just went multiple choice on this, with the entries for 4, 6 and
10 counting 1 point each, and the remainder (including the empty 22) counting
0.2 points each.
- F: The set rooted by 6 is higher, so 6 becomes the parent of 10:
Grading: .5 point for 10's link being 6, .5 point for 6's link being -1, and
1 point for all of the others being identical to part E.
- G: The links for 12 and 0 both change to 6.
1 point for 12, 1 point for 0, 1 point for not saying anything else.
Question 3: 15 points
- Bubble: With bubble sort, you'll keep swapping 186 until you
reach 192. Then you keep swapping 192 until you reach 198. You swap 198 with
131, and you're done:
121 73 79 186 138 16 68 192 131 198
So, the answer is v. One point for w.
- Selection: You will swap 16 and 186, and 68 and 121:
16 68 73 79 192 138 186 121 198 131
So, the answer is b. One point for l. One point for f.
- Insertion: To sentinelize, you first swap 16 and 186.
The vector will be as in answer l. Then, after
two passes, the first four elements will be sorted. Think about that. After sentinelizing,
the lowest element is at index 0. On the first pass of sorting, you'll start with
index 2, because the element at index 1 is already "sorted:"
16 73 79 121 192 138 186 68 198 131
So, the answer is g. If you started with index 1 rather than 2, then you would
get h, so I gave that full credit too. If you didn't sentinelize, then you'd
get either s or t, so I gave half credit for either of those answers.
- Merge: When the first recursive call is done, the first 5 elements will
be sorted, and the last 5 elements will be unchanged:
73 79 121 186 192 138 16 68 198 131
So, the answer is r. Half credit for q, as that's what it looks like after
the second recursive call (just before the merge).
- Bucket: I gave you a 20-element vector on your scratch sheet for you to fill
out. Since the elements are assumed to be uniformly distributed between 0 and 200, you can simply
chop off their last digits to see where they should go in the 20-element vector. If an element
is already there, you look lower, then higher, one slot at a time, until you find an empty
slot. Here's what it should look like when you're done:
When you condense that into one 10-element vector, you get:
16 68 79 73 121 138 131 198 186 192
So, the answer is d. Half credit for e. One point for a.
| a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z |
A | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 54 | 3 | 2 | 11 | 0 |
B | 0 | 58 | 0 | 0 | 0 | 9 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 2 | 2 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
C | 2 | 3 | 2 | 0 | 1 | 12 | 18 | 12 | 4 | 0 | 0 | 3 | 1 | 0 | 0 | 0 | 1 | 1 | 11 | 3 | 0 | 0 | 0 | 0 | 0 | 1 |
D | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 2 | 3 | 2 | 18 | 29 | 1 | 1 | 0 | 0 | 0 | 4 | 7 | 1 |
E | 19 | 0 | 3 | 11 | 5 | 1 | 3 | 0 | 0 | 8 | 4 | 0 | 2 | 4 | 3 | 0 | 2 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 2 |
Question 4: 14 points
Push the value to the end of h and percolate up:
void PQueue::Push(double d)
{
int index, p;
h.push_back(d);
index = h.size()-1;
while (1) {
if (index == 0) return;
p = (index - 1) / 2;
if (h[p] <= h[index]) return;
h[index] = h[p];
h[p] = d;
index = p;
}
}
|
Grading:
- Correct syntax on the first line of the implementation: 2 points.
- h.push_back(d): 2 points
- Exiting at the root: 2 points
- Calculating the parent correctly: 2 points
- Exiting when the parent is less than the child: 2 points
- Swapping otherwise and setting child to parent: 2 poitns
- Nothing extraneous: 2 points
Question 5: 19 points
Outline your solution in English:
This is going to be a power set enumeration. I want to enumerate all subsets of N.
Each subset that I enumerate will represent the number of red balls, and the elements not in
the subset will represent the number of blue balls. I'll calculate those values, and if they
equal r and b, then I return 1. If I reach the end of the enumeration without finding
r and b, I'll return 0. It would save some time were I to total up the elements of
N and making sure that it equals r+b before bothering with the enumeration. You
didn't have to do that.
With 20 elements which can each be 199,999,999, these sums can exceed the maximum value of an
integer. For that reason, your sums should be long long's, rather than integers.
N's size:
A power set enumeration of N elements is O(2N). You start reaching
the 2 second limit in Topcoder at about 222.
Here's an implementation with a main():
(in q5.cpp)
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
int RB(int r, int b, vector <int> &N)
{
long long R, B;
int i, j;
R = 0;
for (i = 0; i < N.size(); i++) R += N[i];
if (R != r + b) return 0;
for (i = 0; i < (1 << N.size()); i++) {
R = 0;
B = 0;
for (j = 0; j < N.size(); j++) {
if (i & (1 << j)) {
R += N[j];
} else {
B += N[j];
}
}
if (R == r && B == b) return 1;
}
return 0;
}
main()
{
int r, b, i;
vector <int> N;
cin >> r >> b;
while (cin >> i) N.push_back(i);
printf("%d\n", RB(r, b, N));
exit(0);
}
|
Grading:
- Answer in English: 5 points
- Constraints: 3 points
- Performing the correct outer loop: 2 points
- Performing the correct inner loop: 2 points
- Calculating R and B: 2 points
- Returning 1 when you find r and b: 2 points
- Using long long for R and B: 2 points
- Returning 0 when you don't find r and b: 1 point