0% found this document useful (0 votes)
11 views3 pages

Final Practice Sols

The document contains practice problems for a CS 31 Algorithms course, focusing on polynomial multiplication, job allocation to machines, pathfinding in directed graphs, and bottleneck analysis in graphs. Each problem includes a detailed solution approach, algorithms, and running time analysis. The solutions utilize various algorithmic techniques including recursion, dynamic programming, and graph theory principles.

Uploaded by

bleeckercoyne
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views3 pages

Final Practice Sols

The document contains practice problems for a CS 31 Algorithms course, focusing on polynomial multiplication, job allocation to machines, pathfinding in directed graphs, and bottleneck analysis in graphs. Each problem includes a detailed solution approach, algorithms, and running time analysis. The solutions utilize various algorithmic techniques including recursion, dynamic programming, and graph theory principles.

Uploaded by

bleeckercoyne
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 3

CS 31: Algorithms (Winter 2025) Final Practice Problems

Give yourself 2 hours and see how many can you do

Problem 1 (Multiplying Many Polynomials).


You are given n univariate polynomials P1 (x), P2 (x), . . . , Pn (x), each of degree n and with integer coeffi-
cients. You want to return the product R(x) := P1 (x)P2 (x) · · · Pn (x) which is also a polynomial.
a. What is the degree of R(x)? Just the exact answer please.
Solution: n2 . When you multiply two polynomials, the degrees add up.
b. Clearly and precisely describe the fastest algorithm you can design which takes in the coefficients of
each polynomial Pi and returns the coefficients of R(x). What is the running time of your algorithm?
Give a short justification of your running time (no need for a full proof). You may assume any
arithmetic operations with integers is O(1) time.
Remark: In class, we saw Karat which multiplied two degree n polynomials in O(nlog2 3 ) time. One can use it to
multiply a degree m polynomial with a degree n polynomial, when m > n, in O(mlog2 3 ) time. You should use this
routine as a blackbox (and not FFT).

Solution: The answer to (a) is n2 .


We consider the polynomials P1 , . . . , Pn stored in a list A[1 : n] and recast the problem which takes a
list A of degree n polynomials and returns their product. We use Karat to denote the Karatsuba algorithm
we learnt in class.

1: procedure MultManyPoly(A[1 : k]):


2: ▷ Each A[i] is a degree ≤ n polynomial.
3: if n = 1 then:
4: return A[1]
5: else if n = 2 then:
6: return Karat(A[1], A[2]) ▷ Takes O(nlog2 3 ) time.
7: else:
8: m ← ⌈k/2⌉
9: R1 ← MultManyPoly(A[1 : m])
10: R2 ← MultManyPoly(A[m + 1 : n])
11: ▷ The degree of R1 and R2 are ≤ ⌈k/2⌉n
12: return Karat(R1 , R2 ) ▷ Takes O((kn/2)log2 3 ) time.

The recurrence guiding the runtime is


T (1) = O(1); T (2) = O(nlog2 3 ); T (k) ≤ 2T (k/2) + O(klog2 3 (n/2)log2 3 )
The key observation is that when considered as a function of k, the “n” (or rather nlog2 3 ) is like a “constant”
multiplier C. The solution to above, as a function of k, is (by Master theorem) T (k) = O(klog2 3 · nlog2 3 ).
When we plug in k = n (that’s what we want), we get the answer O(n2 log2 3 ) = O(nlog2 9 ).
Remark: The slower way of multiplying will be multiplying P1 and P2 , and then multiplying the result with
P3 , and that result with P4 , and so on. Once we have multiplied n/2 polynomials, the degree of the big
polynomial would be Θ(n2 ), and Karatsuba will begin to take O((n2 )log2 3 ) which is O(nlog2 9 ). And this will
be repeated Θ(n) times giving us an algorithm which is n-times slower.

1
Problem 2 (Allocating Jobs to Machines).
You are given 3n jobs and have 3 machines named A, B, C. Each job j has “benefits” a j , b j , c j if assigned to
A, B, or C, respectively. Assume these are positive integers.
Design an efficient algorithm to allocate exactly1 n jobs to each machine such that the sum of benefits of
these jobs is maximized.

Solution: Let the jobs be named 1 to 3n arbitrarily.

• Definition. F(i, j, k) be the maximum benefit that can be obtained from allocating the first (i + j + k)
jobs such that exactly i jobs are on machine A, exactly j jobs on machine B, and exactly k jobs on
machine C. We are interested in F(n, n, n).

• Base Cases. F(0, 0, 0) = 0.

• Recurrence. For i, j, k not all 0:



F(i − 1, j, k) + ai+ j+k if i > 0 

 


F(i, j, k) = max 

F(i, j − 1, k) + bi+ j+k if j > 0 




F(i, j, k − 1) + ci+ j+k if k > 0

 

To clarify, we take the max of all things which “pass” the if-statements.

• Reason. The (i + j + k)th job must be in one of the three machines...and if so, we piggy back to the
residual world. (I am being sketchy here)

• Runtime O(n3 ).

Problem 3 (Adam’s Question).


Adam Douglas is sitting on vertex a in a directed graph G = (V, E). There’s a bar at vertex b of this graph.
Adam has a spaceship named Zaphod which, for any edge (x, y) ∈ E, can go from vertex x to vertex y in
exactly one minute. Once Zaphod begins its journey it runs non-stop for exactly 42 minutes. That is, it can’t
stop at any intermediate point, however, it is allowed to re-visit vertices. Help Adam figure out if he can
visit the bar b. Your algorithm should run in O(m + n) time, where m and n, as usual, are the number of
edges and vertices in G.

Solution: Ok, this is just asking whether or not there is a walk of length exactly 43 from a to b in G.
To solve this, we can make 43 copies of all vertices; name them V0 ∪ V1 ∪ V2 ∪ · · · ∪ V42 . Each vertex v ∈ V
has 43 copies, with copy vi in the set Vi . For each original (x, y) ∈ E, we add 42 edges, namely, (xi , yi+1 ) for
0 ≤ i ≤ 41. In this new graph, H, we need to figure out if there is a path from a0 to b42 . If so, then we have
a walk from a to b of length 42 obtained by “wiping out the subscripts”.
One can also (equivalently) solve this by dynamic programming, a la LBSW, by having d[v, i] ∈ {0, 1} which
is 1 if and only if there is a walk from a to v of length exactly i. We wish to know if d[b, 42] = 1 or not. Base
case: d[a, 0] = 1 and d[v, 0] = 0 otherwise. d[v, j] = 1 if and only if d[u, j − 1] = 1 for some u ∈ V such that
(u, v) ∈ E. Figuring this out takes deg− (v) time, and so figuring out d[v, j] for all v takes O(m) time. Since
0 ≤ j ≤ 42, we get all total O(m) time.
1
if this constraint wasn’t there, then we would allocate j to whichever machine gave the largest benefit

2
Problem 4 (Bottleneck of a Graph).
You are given a weighted directed graph G = (V, E) with every edge having a unique positive capacity w(e).
Assume m ≥ n. Given a path p in G, the bottleneck edge of the path is the one with minimum capacity, that
is,
bottleneck(p) := min w(e)
e∈p

What is the fastest time algorithm you can design to determine the largest value k such that for any two
vertices x, y ∈ V(G), there is some path p from x to y with bottleneck(p) ≥ k?
Bonus: Solve this problem in O(m) time if G is undirected. Y

Solution: In one of the W7 problems, you solved the problem of bottleneck paths: given any s ∈ V, for
every x ∈ V \ s you could find u(x) which is the bottleneck of the largest bottleneck path from s to x using a
modification of Dijkstra; so this can be done in O(m + n log n) time. Let k1 := min x∈V\s u(x); then, for every
vertex x, there is at least one path from s to x with bottleneck ≥ k1 .
Now, we reverse the graph G and run the same algorithm to get k2 . We would then get that for every x,
there is at least one path from s to x in Greverse , that is, a path from x to s in G with bottleneck ≥ k2 . (This
was the same idea as running 2 DFS for figuring out strong connectivity). The answer we are looking for is
k := min(k1 , k2 ) – for any x and y, there is a bottleneck ≥ k path from x to s and another from s to y. If we
take the concatenation of these paths to get a walk, and find the path from x to y by short-cutting, this path
will have bottleneck ≥ k as well.
Bonus. (Sketch). There are two-three main ideas:

• First, given a k we can check in O(m) time if for every x and y there is a path with bottleneck at
least k: we first take O(m) time and delete all edges of capacity ≤ k getting a graph Gk . Run strong
connectivity on the remainder. If Gk is connected, then the answer we are looking for is ≥ k, and we
recurse on Gk .

• If Gk is not connected, then the answer we are looking for is < k. Cruciall ynote: we can contract, a la
Boruvka, all components in Gk . This is where undirected-ness is being used. Let this resulting graph
be Hk and we need to recurse our problem on Hk .

• So, if we can find a k such that no matter what case we land in, the resulting graph has “half” the
edges, then we would be done. So, we pick k to be the median of all edge weights — this can be done
in O(m) time as well! So, the full algorithm is

a. Find the median weight k in O(m) time.


b. Construct Gk which deletes edges with weight < k. This takes O(m) time.
c. Find connected components of Gk in O(m) time by DFS.
d. If there is only one connected component, we recurse in Gk . This takes at most T (m/2) time
since Gk has ≤ m/2 edges.
e. Otherwise, we contract all connected components of Gk to get Hk , and we recurse in Hk . Since
at least m/2 edges are contracted, the number of edges in Hk is at most m/2. So this takes at
most T (m/2) time.
f. So the recurrence is T (m) ≤ T (m/2) + O(m) which evaluates to O(m).

You might also like