ADE 16-17 Sol
ADE 16-17 Sol
These may be updated. Please let us know if there are any problems.
(a) Explain, and give pseudo-code for, Dijkstra’s algorithm to find the shortest path in an
undirected graph when the distances for edges are given and all are non-negative.
Your answer should include a brief explanation of why it always gives an optimal
(shortest) path (if one exists).
Then use Dijkstra’s algorithm to find the shortest path from node B to node E in the
graph below. Show your working, including the open and closed lists at each stage.
4 A
8
B
D
9 C 6
4
14
E F
3 (10 marks)
ANSWER:
Code is standard from lectures, roughly
PQ q
q.add(start node)
while ( ! q.isEmpty() ) {
u ( c ) = pq.pop() // remove first node with its cost
close(u)
if u == target node then return c.
for each non-closed neighbour v of u
pq.add( u with cost c + weight(uv) ) // or readjust cost if it is already there
}
The method is complete and correct, assuming that nodes can be reached, because it works
outwards in distance reachable. When nodes are popped from the PQ, then the distance to them
is optimal, because other entries in the PQ will have larger distances to them, and because
edges are non-negative none of their neighbours can get there faster.
Open: Closed
B(0)
A(4), C(9) B(0)
C(9), D(12) A(4)
D(12),E(23) C(9) note D(15) is also achieved, but worse than D(12)
F(16),E(23) D(12)
E(16+3=19), E(23) F(16)
pop E reaches the goal in 19, with the path B-A-D-F-E
Note: vital not to take the first time that reach E, at E(23).
G52ACE-E1
Page 3 of 13 G52ACE-E1
(b) Explain, and give pseudo-code for, the Floyd-Warshall algorithm to find the lengths of
the shortest paths between each pair of vertices in a graph. The graph can have a mix
of directed and bidirectional edges, but you can assume the distances are such that
there are no negative cycles.
Your answer should include a brief explanation of why it always gives an optimal path
for each pair of vertices.
Then use the algorithm on the graph below to find the matrix of all-pairs of shortest
paths. Show your working.
2
n0
n2
9
4
n1
(10 marks)
ANSWER:
HISTORIC NOTE: in the year (2016-17) the FW work assumed that self-loops are not
included, and so the distances from nodes to themselves started as infinity. This
convention was changed in subsequent years, including 2018-19, to be the convention
that self-loops can be assumed, and so the diagonal elements would start with 0.
(This is consistent with the assumption used in Dijkstra that all nodes can reach
themselves in zero distance – the shortest path from a node to itself is zero.)
YOU SHOULD NOW ASSUME THAT ALL NODES HAVE A SELF-EDGE OF 0 – as in the
lectures and tutorials. The computation below is using this current convention.
code is that
This is correct because the recurrence relations are correct. A fundamental property of paths is
that if we go from i to j via k, then we can use the optimal from i to k, and the optimal from k to
j.
d(i,j,0) = w(i,j) =
0 9 2
9 0 Inf
2 4 0
d(i,j,1) = d(i,j,{n0}) = only the path from n1 to n2 gains; changing to min(Inf, 9+2)=11
0 9 2
9 0 11
2 4 0
0 9 2
9 0 11
2 4 0
Finally, also allow n2, and so now all nodes are allowed as via node.
0 6 2
9 0 11
2 4 0
G52ACE-E1
Page 5 of 13 G52ACE-E1
2. This question is concerned with string matching algorithms. (20 marks total)
Consider the algorithm LastMatch below, which returns the offset (shift) of the last
occurrence of the pattern P in text T, or -1 if P does not occur in T:
LastMatch(T,P)
for(s = T.length - P.length downto 0)
j = 1
while(j =< P.length and P[j] == T[s + j])
j++
if(j == P.length + 1)
return s
return -1
(a) State a suitable precondition for LastMatch in English, and a suitable postcondition in
predicate calculus.
(6 marks)
ANSWER:
<precondition: T is an array of n > 0 characters
P is an array of m > 0 characters>
that is, the characters in the subarray P[1 … j] match the corresponding characters in
the subarray T[s ... s + j].
A suitable invariant for the outer for loop is
G52ACE-E1
Page 7 of 13 G52ACE-E1
(c) In automata-based string matching, a string matching automaton is constructed that
recognises the pattern. Draw the automaton that recognises the pattern P = abac,
where the input alphabet is Σ = {a b c}. (Note: you don’t need to show failing edges
that return to state 0.)
(5 marks)
ANSWER:
(a) Give the definitions of big-Oh, big-Omega, big-Theta, and little-oh by completing each
of the following:
i) ‘big-Oh’: f(n) is O( g(n) ) ….
ii) ‘big-Omega’: f(n) is Ω( g(n) ) ….
iii) ‘big-Theta’: f(n) is Θ( g(n) ) ….
iv) ‘little-oh’: f(n) is o( g(n) ) ….
(5 marks)
ANSWER:
Standard. Expect the definitions from the lectures. That is, in abbreviated form
f(n) is O( g(n) ) iff exists c, c>0 and n0 s.t forall n >= n0. f(n) <= c g(n)
f(n) is Ω ( g(n) ) iff exists c > 0 n0 s.t forall n >= n0. f(n) >= c g(n)
f(n) is Θ ( g(n) ) iff exists c’ > 0, c’’, n0 s.t forall n >= n0. c’ g(n) <= f(n) <= c’’ g(n)
f(n) is o ( g(n) ) iff forall c > 0 exists n0 s.t forall n >= n0. f(n) < c g(n)
This is standard Knowledge, but is asked because often students get these wrong – e.g. mixing
up the ordering of quantifiers, or the inequalities.
(b) Give appropriate descriptions in terms of each of `O’ (big-Oh) and `Ω’ (big-Omega) of
the function
f(n) = 2 n2 + 5 n log( n4 )
You should justify your answers, but do not need to give proofs. (5 marks)
ANSWER:
The second term is the smaller one as it is just n log n, and the log n is dominated by n.
The coefficient does not matter. Hence, it is equivalent to f(n) = n2 Hence, is both O and Omega
of n2.
Note a common mistake is to think that Omega needs the smaller term.
f(n) = 2 n + ( n2 % 10 )
where “n2 % 10” uses the usual modulus operator, e.g. 72 % 10 = 9, etc.
Get only partial marks if get right answer but do not do “From the definitions” and instead just
drop the smaller term.
4. This question is concerned with MSTs in weighted undirected graphs. (20 marks total)
Firstly it is a spanning tree. So it uses a subset of the edges to create a tree that connects
together all the vertices. Then it is minimal in that when we consider the total weight of the
edges used, then no other spanning tree has a smaller value.
(c) Give an argument that Prim’s algorithm is correct, i.e. that it will always find an MST.
Hint: consider partitioning the nodes into two sets V1 and V2 and consider the edges
between them.
(5 marks)
ANSWER:
Given a partition, consider the set of edges that go between V1 and V2. Suppose that an edge e
has a minimum weight within that set, then that edge will be part of some MST. Proof is by
contradiction, if it is not minimum then could replace it with a smaller edge from the set and so
have a better spanning tree. Hence in Prims algorithm
V1 = MST so far
V2 = the other nodes
and this demonstrates it adding a minimum edge will still allow to be in an MST.
(d) Suppose that all the weights on the graph are different. I.e. that no two edges have the
same weight. In this case argue that the MST is unique.
Hint: consider the partition used in part c.
(5 marks)
ANSWER:
Consider any partition V1 V2, then the minimal edge between the two partitions is unique as all
the edges are different weights. But only the minimal edge is in the MST – otherwise we could
reduce the weight by switching to a lower-weight edge. Hence if we consider all partitions the
edge of the MST is forced. Hence there cannot be any freedom in constructing it.
G52ACE-E1
Page 11 of 13 G52ACE-E1
Only partial marks for just pointing out that Prim’s algorithm will have no arbitrary choices from
a given starting node, but does not cover the issue of whether a different MST would result from
a different starting node.
(a) Explain, and give pseudo-code for, the merge-sort algorithm to sort an array A[] of
integers into ascending order.
Show the working of the algorithm on the array A = [ 4 8 9 2 1 7 3 6 ]. Give the tree
representing the execution of the algorithm.
State the worst case runtime of mergesort, of an array of n entries, in big-Oh notation,
and give a justification of your answer.
(9 marks)
ANSWER:
mergesort(A) {
divide A into left L and right R arrays
mergesort(L)
mergesort(R)
A = merge(L,R)
}
where the merge algorithms considers the two sorted arrays L and R, and then takes the
smallest start entry of each.
[ 4 8 9 2 1 7 3 6 ].
[ 4 8 9 2 -> 2 4 8 9 ] [ 1 7 3 6 -> 1 3 6 7]
(b) Explain, and give pseudo-code for, the quicksort algorithm to sort an array A[] of
integers into ascending order.
Both mergesort and quicksort are in the divide-and-conquer class of algorithms, but
describe how they take a different approach to the ‘divide’ and to the ‘conquer’ steps.
(7 marks)
ANSWER:
qs( A ) {
p = pivot(A)
G52ACE-E1
Page 13 of 13 G52ACE-E1
(L,R) = partition(A,p)
qs(L)
qs(R)
}
where the partition works on the array to ensure all elements < p are in the left side L, and all
>= p are in the right side.
For the ‘divide’ : mergesort takes a trivial split, and quicksort has a specific partition step
For the ‘conquer’ : mergesort needs a non-trivial merge, but the conquer in quicksort requires
no work, but is automatic.
(c) Suppose that the pivot is selected randomly from within the array. Briefly outline a proof
that the resulting average case complexity is O(n log n)
(4 marks)
ANSWER:
Because 2/3 of the time it will be in the middle 1/3 of the range. So the execution tree will be of
expected depth O( log n). Hence, similar argument to part (a).