Exercises
9.1.1
Hints.
- Use quotient and mod operations.
- Observe why the quotient yields the maximum possible count of some coin.
Solution.
# input: non negative amount n, and a decreasing array of coins D
# output: array C where C[i] is number of coins of ith denomination D[i]
def greedyCoins(integer n, D[1..m])
# for each coin
for i in 1..m
# take max possible number of it
C[i] = floor( n/D[i] )
# remaining amount for next iteration
n = n \mod D[i]
# if there is still a remaining amount
if n != 0 return "no solution"
# otherwise given n is partitioned by coins
return C
9.1.15
Homework.
9.2.3
Hints.
- Observe
Kruskal
works with global edges, unlikePrim
which searches within local neighbour edges. - What is error you think we will encounter upon running
Kruskal
on a a tree with more than one component? - Why does looping on $|V| - 1$ works in
Kruskal
? - Modify the
while
condition to accommodate any forest.
Solution.
Modify the while
condition in Kruskal
to be ecounter < |E|
, So it terminates if there are no more edges.
Bonus. Modify Prim
then use it as a subroutine to solve the general forest case.
9.2.5
Homework.
9.3.1
Hints.
- (c) Use Transform-and-conquer strategy.
- (c) Fixing vertices, What kind of modification is required on edges?
- (d) Use Transform-and-conquer strategy.
- (d) We will use Dijkstra as a subroutine, So the graph will be transformed to the usual form given in the book.
Solution.
(a)
A data structure which considers directed edges.
(b)
Same algorithm. You may terminate once you find the destination.
(d)
Each vertex $v_i$ is mapped to $v_i^{st}$ and $v_i^{en}$, with directed edge $( v_i^{st}, v_i^{en} )$ whose weight is the number labeled on $v_i$. Any vertex in $G$ neighbour to $v_i$, can travel to $v_i^{st}$ but not $v_i^{en}$ in $G'$. Only vertices $v_i^{en}$ but not $v_i^{st}$ can travel to other vertices. Those edges in $G'$ are assigned zero weights.
# input: graph G with weighted vertices
# output: graph G with weighted edges and no weighted vertices
def vertexWeightToEdgeWeight(G)
construct empty graph G'
for each vertex v in G(V)
add vertex v_st to G'
add vertex v_en to G'
set (v_st, v_en).weight to v.weight
add edge (v_st, v_en) to G'
for each edge e = {a,b} in G(E)
set (a_en, b_st).weight = 0
add edge (a_en, b_st) to G'
set (b_en, a_st).weight = 0
add edge (b_en, a_st) to G'
return G'
(c)
Set the destination as source then reverse paths. If graph is directed reverse paths before running the algorithm also.
# input: graph G
# output: same graph but whose edges are reversed
def reverseEdges(G)
construct empty graph G'
clone vertices G'(V) = G(V)
for every vertex v in G(V)
for every edge e = (v,t) in G(E)
add edge (t,v) to G'
return G'
# input: undirected graph G, destination d
# output: shortest-paths of given d
def undirectedGraphSingleDistination(G, d)
compute Dijkstra(G, d) in graph G
return reverseEdges(G)
# input: directed graph G, destination d
# output: shortest-paths of given d
def directedGraphSingleDestination(G, d)
G = reverseEdges(G)
compute Dijkstra(G, d) in graph G
return reverseEdges(G)
Homework.
A data-structure based implementation is left to students. In fact this is an excellent illustration of abstraction in algorithm design.
9.3.7
Homework.
9.4.5
Homework.
9.4.7
Hints.
- A basic recursive algorithm traversal works.
Solution.
def allHuffmanCodes(root)
if root is NULL
return [ ]
# if root is a leaf
if root.rightChild is NULL and root.leftChild is NULL
return [ root.character ]
# if exactly one child is NULL, Concatenating an empty list does no harm
childCodes = allHuffmanCodes(root.leftChild) + allHuffmanCodes(root.rightChild)
# prefix each code in child with root's character
return [ root.character + code for code in childCodes ]
We leave it to students to modify the algorithm so that it generates a 2d-array of symbols-codes as a homework.