CS302 2022 Final Exam Answers and Grading
Questions 1 - 9
These were presented in random order. I'll incude the questions here so you can find
yours.
- Which algorithm is used to find shortest paths in an unweighted, undirected graph?
Breadth-First Search: #3.
- Which algorithm can be used to identify the connected components of an unweighted, undirected graph in O(|V|+|E|) time? You can use either depth or breadth first search
for this, so #2 and #3 are fine answers. You can also use
disjoint sets, but the running time for that will be O(E alpha(V)),
so you get 0.7 points for that answer.
- I have a network of pipes that connect junctions. Each pipe has a length and a diameter. In my control center, I can turn pipes on and off. I am at junction A, and I have been given a chemical that will improve the longevity of each junction. I want to deliver the chemical to each junction. The problem is, that the chemical corrodes the pipes, so I want to minimize the inner surface area of pipes that the chemical touches. What algorithm should I use to determine what pipes to use?
This is minimum spanning tree of a weighted graph: #7.
- Which algorithm can be used to find the maximum matching of a bipartite graph?
This is your word-dice lab: Network Flow: #8.
- Which algorithm can be used to find shortest paths in a weighted, directed acyclic graph in O(|V|+|E|) time? Topological Sort: #9.
- Which algorithm is used to find the augmenting paths in the Edmonds-Karp algorithm?
Breadth-First Search: #3.
- Which algorithm is used when you are processing the sorted edges in Kruskal's algorithm?
Disjoint sets: #1.
- Which algorithm maintains a multimap of nodes, keyed on distance to a starting node?
Dijkstra's algorithm for shortest paths: #4.
#5 and #6 keep a multimap keyed on flow, not shortest paths.
- Which algorithm can be used to find the minimum cut of a weighted graph?
Network Flow: #8.
Grading
2 points per question.
Question 10
These came from a bank. I'm going to answer the one in
Exam.pdf.
Let's process. We start with node B, whose distance is 16. Here are paths going through
node B:
C D E F G H I J
24 42 45 - - 46 35 114
So we:
Add D-42
Add E-45
Add J-114
Change C-24
Change H-46
Change I-35
|
Now node C with a distance of 24:
D E F G H I J
- - - - 70 48 -
That adds and changes nothing. Now G with a distance of 28:
D E F H I J
49 81 - 35 - -
That changes H:
Now I with a distance of 35:
D E F H J
- - 48 - 132
So that adds F:
That's four adds and four changes, so we're done.
Grading
To help with partial credit, I divided the grading into six parts:
- Number of nodes that you added correctly. Each correct node
was worth 0.625 points, so this part was worth 2.5 points.
- Number of nodes that you changed correctly. Each correct node
was worth 0.625 points, so this part was worth 2.5 points.
- Number of distances that you added or changed correctly, plus
or minus one. For example, if you said "A-35", and one of the
correct distances was 34, 35 or 36, then that's a match. You
can't match the same distance twice, so if you had "A-25" and "B-25",
but there was only one correct distance that was 24, 25 or 26, then
that's only one match. Each match was worth 0.625 points for a
total of 5 point.
- Number of node-distance combos that were correct for adds or changes,
regardless of order. Each of these was worth 0.375 points, for
a total of 3 points.
- Number of node-distance combos that were correct for adds and in
the right place -- that means that your first add had to be the
correct first add, etc. Each of these was worth 0.375 points, for
a total of 1.5 points.
- Number of node-distance combos that were correct for changes and in
the right place. Each of these was worth 0.375 points, for
a total of 1.5 points.
The details of your answers are part of the grading information sent to
you, broken out into its own place. Look for it. The "answer key" is
the non-zero weights on your adjacency matrix for node A, concatenated
into a string. So, for example, if your adjacency matrix was:
A B C D E F G H I J
--- --- --- --- --- --- --- --- --- ---
A | -- 16 60 -- -- -- 28 82 65 --
B | 78 -- 8 26 29 -- -- 30 19 98
C | -- 50 -- -- -- -- -- 41 24 --
D | 31 54 12 -- 49 96 78 -- 44 --
E | -- 5 62 16 -- 88 47 -- -- --
F | 59 1 -- -- -- -- 38 -- -- 91
G | 10 74 20 21 63 -- -- 7 -- --
H | 16 -- 34 -- 100 97 15 -- -- --
I | -- 74 42 -- -- 13 -- -- -- 87
J | 48 -- -- 2 -- -- 82 43 70 --
Then your key is "1660288265".
Question 11
These came from a bank. I'm going to answer the one in
Exam.pdf. I'll include the question in italics:
You are sorting the following string using quicksort, with median-of-three pivot selection:
FBRRBABABBB. In the very first partition, what is the pivot?
- The first character, 'F'
- The last character, 'B'
- The middle character, 'A'
So, the answer is: B.
You are sorting the following string using quicksort:
MZYTWQIAELBOK
Suppose you use the first character, 'M', as a pivot. Please show what the string looks like after you have done the first partition, but before you swap 'M' into place.
- Swap Z and K: MKYTWQIAELBOZ
- Swap Y and B: MKBTWQIAELYOZ
- Swap T and L: MKBLWQIAETYOZ
- Swap W and E: MKBLEQIAWTYOZ
- Swap Q and A: MKBLEAIQWTYOZ
- You're done: MKBLEAIQWTYOZ
You are sorting the following string using quicksort, using the first character, 'H', as the pivot:
HBHKHCBCBUHYC
Show what the string is after you partition, before you swap 'H' into place.
- Swap (the second) H and C: HBCKHCBCBUHYH
- Swap K and H (third from the end): HBCHHCBCBUKYH
- Swap H and B (the third): HBCHBCBCHUKYH
- You're done: HBCHBCBCHUKYH
You are sorting the following string using mergesort:
FXRIJCAKUWSZ
Please enter what the string is before you perform the final merge.
- The first half is FXRIJC and the second half is AKUWSZ.
- Sort the first half: CFIJRX
- Sort the second half: AKSUWZ
- The answer is their concatenation: CFIJRXAKSUWZ.
Grading
4 points per part. I have the answers specific to your questions in the
grading file that I sent you, so that you can see the correct answers.
Question 12
These came from a bank. I'll answer the one in
Exam.pdf. There is a typo in that PDF (which I fixed
before the exam) -- it has two part 3's -- just fix it mentally.
Part 1: The answer was the same on all questions -- the shortest path from
S to T is SCFT.
Part 2: Edge EF is the limiting one -- the flow is 18.
Part 3: This is the edge SC, whose weight is 66-18 = 48.
Part 4: The edge FT.
Part 5: Its new weight is 53-18 = 35.
Part 6: These are the reverse edges: CS, FC and TF.
Part 7: Their flow is 18.
Part 8: This isn't hard to eyeball, since CF, DF and ET are so much smaller
than the others. It should be clear that they make a cut, so their sum is the
maximum flow: 18+12+19 = 49.
Part 9: As specified above: CF, DF and ET.
Grading
You should be able to figure out how your problem maps to the one above to check your
grade.
- Part 1: 2 points
- Part 2: 2 points -- had to be the flow of your path
- Part 3: 2 points -- had to work with your answer to Part 1
- Part 4: 0.5 points -- had to be an edge that's not the cut edge and not from S
- Part 5: 0.5 points
- Part 6: 2 points -- 0.7 if you only got one edge right
- Part 7: 1 point -- had to equal your answer to part 2 (and be a reasonable value)
- Part 8: 3 points: Sum up edges CF, DF and ET.
- Part 9: 3 points: One for each of CF, DF and ET. O points if you gave more than three
edges.
Question 13
Again from a bank. Here's the one in Exam.pdf:
We have an undirected, weighted graph with eight nodes, A through H. I specify it below by listing the edges and their weights. There are four columns, and each column has the edge and then its weight.
GH 10 FG 34 AE 50 CG 73
BC 16 CD 35 AD 56 DE 84
FH 21 DG 40 CE 59 EG 89
CH 23 AF 41 BE 65 AG 92
AC 24 AH 43 CF 69 DH 95
BF 32 EH 47 DF 70 AB 98
BD 33 BH 49 BG 71 EF 99
|
Please enter the minimum spanning tree of this graph. List the edges separated by spaces.
Best to go through Kruskal's algorithm, since the edges are sorted. I'll show the disjoint sets
to the right
ABCDEFGH
GH ......xx
BC .yy...xx
FH .yy..xxx
CH .xx..xxx
AC xxx..xxx
BF xxx..xxx Ignore
BD xxxx.xxx
FG xxxx.xxx Ignore
CD xxxx.xxx Ignore
DG xxxx.xxx Ignore
AF xxxx.xxx Ignore
AH xxxx.xxx Ignore
EH xxxx.xxx
|
The answer is:
Grading
You'll see your grading as something like:
AE-AF-DG-AD-AH-BH-BC-matches-6-misses-1
|
The initial part is the minimum spanning tree for your problem, and then how
many edges you had right and wrong. Grades were:
- "matches-7-misses-0" - 14 points
- "matches-6-misses-1" - 12 points
- "matches-6-misses-0" - 11 points
- "matches-7-misses-1" - 11 points
- "matches-5-misses-2" - 9 points
- "matches-5-misses-0" - 8 points
Question 14
Here's a commented answer, in
14-answer.cpp
#include <string>
#include <vector>
#include <list>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
using namespace std;
/* I just made this up so I can test. */
double cost(const string &s1, const string &s2, int n)
{
size_t i;
double j;
double val;
val = 0;
for (i = 0; i < s1.size(); i++) val += s1[i];
for (i = 0; i < s2.size(); i++) {
j = s2[i];
j /= 26.0;
val += j;
}
val += ((n%7)*(n%7));
return val;
}
/* Global variable is poor form, but this is an exam and I said it was ok. */
map <string, double> Cache;
double mincost(const string &x, const string &y, int z)
{
string key;
char sz[20];
bool isset;
double rv, rec;
/* Base case */
if (z == 0 && x.size() == 0 && y.size() == 0) return 0;
/* Make the cache string and check the cache. You need a delimeter between
x and y, otherwise you can't differentiate (x = "a", y = "bc") from
(x = "ab", y = "c"). */
key = x;
key += ":"; // You can use any delimiter that is not a lowercase letter.
key += y;
key += ":"; // This is unnecessary, but I'd include it to help debug.
sprintf(sz, "%d", z);
key += sz;
if (Cache.find(key) != Cache.end()) return Cache[key];
/* If it's not in the cache, make the recursive calls, but don't add the cost in yet. */
isset = false;
if (x.size() > 0) {
rv = mincost(x.substr(0, x.size()-1), y, z);
rec = mincost(x.substr(1, x.size()-1), y, z);
if (rec < rv) rv = rec;
isset = true;
}
if (y.size() > 0) {
rec = mincost(x, y.substr(1, y.size()-1), z);
if (!isset || rec < rv) rv = rec;
isset = true;
}
if (z > 0) {
rec = mincost(x, y, z-1);
if (!isset || rec < rv) rv = rec;
}
/* Add the cost at the end. */
rv += cost(x, y, z);
/* Set the cache and return. */
Cache[key] = rv;
return rv;
}
int main()
{
string x, y;
int z;
if (!(cin >> x >> y >> z)) exit(0);
cout << mincost(x, y, z) << endl;
return 0;
}
|
Grading
This was a straightforward program, but many of you got tripped up with
small things. Had everyone been strapped for time, I'd be more lenient
with the grading, but pretty much everyone ended early, so you had the
time to get the details correct.
You started with 16 points, and were deducted for things that were wrong.
Common deductions:
Key never created: -5
Linearly searching a map: -5 -- You should know never to do that.
No type specifications in mincost(): -3
Setting incorrect values in the cache (usually by setting them
inside the if statements): -2
Cache never used: -2
cost() is only called in the main(): -2
No main(): -2
Z is not in the key: -2
Using uninitialized variable(s) when if statements are false: -2. A lot of you did this.
Wrong base case (some of you liked to ignore z): -2
Using argc/argv instead of standard input: -1 -- please read the instructions...
Multiple calls to cost() -- you only needed to call cost() once inside
of mincost(). Who knows how expensive it is, so you should only call
it once: -1
Strings should be reference parameters. No need to make extra copies
of memory when you don't need them. -1
No delimiter in the memoization key -- you need somethinge between
x and y in the key. Otherwise, you can't differentiate x = "", y = "a"
from x = "a", y = "".
Using a char limits z to a max of 127. Some of you did something like
key = x + " " + b + (char) z. That compiles and runs, but limits z.
Fixed size buffer limits the size of x and y. If you're using sprintf,
you'd do better to just use it for z, where you know the max size.
Uses a sentinel. I didn't specify what cost() returns, so you can't
use any value as a sentinel. There are better ways to handle it,
like I did above. A bunch of students used sets to hold the answer
and then return the first one on the set -- that was very nice!
Question 15
The first question:
Your cache can have all substrings of x, all suffixes of y, and all values
from 0 to z. So the answer is O(X2YZ). If you set up your cache incorrectly on the previous question, then you are likely to have gotten this question wrong.
The second question: shortest path on a directed, acyclic graph (since we deleted the
roads that go south or east). So, this is topological sort. O(C+R).