Question 1:

Part 1: With selection sort, you should be swapping the smallest element with the first element at iteration 0, and the second-smallest element with the second element at iteration 1.

With insertion sort, iteration 1 will sort the first two elements, and iteration 2 will sort the first three elements.

It's possible for the output to be both.

• Output A: This is insertion sort.
• Output B: Also insertion.
• Output C: Selection. Iteration 0 could be either, but iteration 1 differentiates it.
• Output D: This is neither.
• Output E: Also neither.
• Output F: Selection.
Part 2: The median of the first, middle and last element is 619. So, we swap that to the front:
```619, 983, 036, 783, 734, 186, 494, 469, 251
```
We set l = 1 and r = 8. The elements at those pointers are in the wrong partition, so we swap them:
```619, 251, 036, 783, 734, 186, 494, 469, 983
```
We increment l until we get to an element that is too big: l=3. And we decrement r until we get to an element that is too small: r=7. And we swap:
```619, 251, 036, 469, 734, 186, 494, 783, 983
```
One more increment and decrement. l = 4 and r = 6. Swap:
```619, 251, 036, 469, 494, 186, 734, 783, 983
```
Increment l until it equals 6. Decrement r until it equals 5. You're done. Swap elements 0 and 5. Here's the final answer:
```186, 251, 036, 469, 494, 619, 734, 783, 983
```

Part 1: 12 points -- two per part.

Part 2: 6 points -- rubrick as follows:

• Two points if you gave a valid partition about 251 or 619.
• Two more points if you gave a valid partition about 619.
• Two more points if you gave the partition in the correct order.

Question 2: Dynamic Programming

You need to add a cache. You need to test it in the beginning of gc(), and whenever you return, you need to add the return value to the cache before you return. You don't need to do this in the first return statement, because there are no recursive calls before that first return statement.

How you index the cache is a concern, because you need to index it both by the string and by zero. In my answer code, I convert them both into a string using a stringstream. However, you could have an array of two caches -- one for zero = 0, and one for zero = 1.

You cannot use a vector indexed on s.size(), because the string changes from call to call (with news).

• Did you add a cache: 3 points
• Was the cache keyed on s: 2 points
• Was the cache keyed on zer : 2 points
• Did you try to return an answer from the cache first: 3 points
• Correctly handling the second return: 2 points
• Correctly handling the last return: 3 points

Question 3: Network flow

You were asked to process an augmenting path through a graph while doing network flow. That means you need to figure out the residual flow in the path, and then subtract it from the residual, add the reverse flow to the residual, and add the flow to the flow graph.

There is a subtlety in adding the flow to the flow graph -- if there is flow in the reverse edge, you need to take flow out of the reverse edge, and then if there is any left, you add it to the flow of the non-reverse edge.

 ```void Graph::Process_Augmenting_Path(vector path) { int i, f; Edge *e, *r; /* Figure out the flow in the path */ f = path[0]->residual; for (i = 1; i < path.size(); i++) { if (path[i]->residual < f) f = path[i]->residual; } /* Add flow to the flow graph (which means you may have to reduce flow on a reverse edge. Also process the residual -- add flow to the reverse edge's residual, and subtract it from the edge's residual. */ for (i = 0; i < path.size(); i++) { e = path[i]; r = e->reverse; if (r->flow >= f) { r->flow -= f; } else { e->flow = (f - r->flow); r->flow = 0; } e->residual -= f; r->residual += f; } } ```

Points were allocated roughly as:
• Calculating the flow: 5 points
• Subtracting the flow from the residual: 3 points
• Adding flow to the residual reverse edge: 3 points
• Adding flow to flow: 3 points
• Correctly handling positive flow along the reverse edge: 2 points.

Question 4: Running Time

Because each node's adjacency list is ≤ 10, |E| = O(n). Thus, things like O(|V| + |E|) become O(n), and O(|V|log(|E|)) become O(n log n).
• A: O(n log n).
• B: This is DFS: O(n).
• C: Power set -- you can represent a subset with an n-bit number: O(2n).
• D: Edmonds-Karp uses BFS: O(n).
• E: O(n)
• F: Dijkstra's algorithm: O(n log n)
• G: This is also DFS: O(n)
• H: O(n)
• I: The limiting activity is sorting the edges: O(n log n)
• J: This is BFS: O(n)
• K: This is the number of permutations: O(n!)
• L: O(n)

1.5 points per answer. There was a little partial credit:
• You got 1 point for O(n α(n)) on B.
• You got .5 points for O(n!) on C.
• You got .5 points for O(n α(n)) on I.
• You got .5 points for O(2n) on K.
Here are the individual answers -- red is wrong, yellow is right:

Question 5: Graph Algorithms

• Part A: The easiest thing here is to use Kruskal's algorithm, because the edges are sorted already. You can draw the graph (or draw on top of the graph in the question). You start with FI, DH, FH, AE, AG, HJ, and GJ. At that point, here's the graph:

The edge EH is next, but it is within the same connected component, so we throw it out. The next three edges, BC, BE and HL, also work:

At this point, the only node that is no longer in the spanning tree is node K, so we throw out edges BE, HL, CI, EI and CE. The last edge is JK.

The answer is FI, DH, FH, AE, AG, HJ, GJ, BC, BE, HL, JK.

• Part B: When you start with node A, the multimap is:

(5,E),(6,G),(42,B),(84,C),(94,D)

We process node E (distance 5), which updates the multimap as:

(6,G),(16,H),(22,B),(28,I),(33,C),(49,F),(57,D)

We process node G (distance 6), which updates the multimap as:

(15,J)(16,H),(22,B),(28,I),(33,C),(49,F),(54,D),(82,K)

We've now reached J, so we're done. The final answer is:

(16,H),(22,B),(28,I),(33,C),(49,F),(54,D),(82,K)

• Part C: You can do a Modified Dijkstra here, or frankly, you can eyeball the adjacency matrix. The maximum edge incident to J has flow 85, and the maximum edge incident to C is 84, so any path with a flow of 84 will be maximum. You can see that CA,AD,DJ has a flow of 84. That's it!

• Part D: Keep a table of the maximum weight paths to B, C, D, E and F, and process the nodes in that order:

 Path to B Path to C Path to D Path to E Path to F Process Node A 42 (A->B) 84 (A->C) 94 (A->D) 5 (A->E) - Process Node B Done 84 (A->C) 140 (A->B->D) 59 (A->B->E)/td> 95 (A->B->F) Process Node C Done Done 140 (A->B->D) 112 (A->C->E) 124 (A->C->F) Process Node D Done Done Done 192 (A->B->D->E) 124 (A->C->F) Process Node E Done Done Done Done 236 (A->B->D->E->F)

The answers are on the diagonal of the above table.