Prim’s Algorithm
Proof of Correctness
Prove that Prim’s Algorithm always generates the MST for any given graph .
Base Case
When the algorithm starts, the tree generated must be a subtree of the MST because only one node is in the tree.
Inductive Step
Assume that at step , the tree generated is a subtree of the MST. At step , partition the nodes into two sets, those in the tree already as and those not as . The edge added must be the shortest between and because any other edge will increase the cost of the MST. This is exactly what Prim’s choose and therefore, the tree generated is still a subgraph of the MST.
This assumption holds until all nodes are included in the MST. Thus, by mathematical induction, Prim’s algorithm always generates the MST for any given graph .
Dijkstra’s Algorithm
Pseudocode
function reconstruct(pred: dict, x: node):
path = []
prev = x
while prev != null:
path.add(prev) to front of list
prev = pred[prev]
return path
Algorithm dijkstras(s: node, x: node, G: graph):
// s is the source node, x is the destination node
for node n in G:
dist[n] = inf
pred[n] = null
dist[u] = 0
Q = MinPrioQueue based on dist values of nodes
while Q is not empty:
u = top(Q)
Q = dequeue(Q)
if u = x:
return reconstruct(pred, x)
for each unvisited neighbour v of u:
tempDist = dist[u] + weight(u,v)
if tempDist < dist[v]:
dist[v] = tempDist
pred[v] = u
return reconstruct(pred, x)
Proof of Correctness
Let be a set of vertices whose shortest distances have been finalised by Dijkstra’s and let be the source node.
Prove that Dijkstra’s Algorithm always finds the shortest path from the node to every other node for any given graph , provided that has no negative edge weights.
Base Case
When the algorithm starts, the distance from the source node to itself is zero, which is the shortest distance possible assuming no negative edge weights. Thus, the algorithm holds for the base case.
Inductive Step
It must be proved that Dijkstra’s holds true for all vertices not . Consider the step in Dijkstra’s algorithm where the node is added to via the edge where .
Assume for the sake of contradiction that a shorter path to exists via some other path. The path must then take the form , where is in and is not in . Since there are no negative weights, the cost of the path is . When selecting a vertex to finalise, Dijkstra’s selects the non-finalised vertex with the shortest path. As such, because the node is selected by the algorithm via . Therefore, which contradicts the above assumption that a shorter path exists. Hence, Dijkstra’s algorithm correctly finds the shortest distance to the node via the edge .
Thus, by mathematical induction, Dijkstra’s algorithm correctly calculates the shortest distance from the node to all other nodes in the graph.
Bellman-Ford Algorithm
Proof of Correctness
Prove that the Bellman-Ford Algorithm always finds the shortest path from the node to every other node for any given graph , provided that has no negative cycles.
Base Case
At the start this must be true, because only the node is marked as 0 distance.
Inductive Step
Assume that at step , the shortest path from to any node steps away are correct. At the step , all edges are checked to see if it can improve the shortest path distance to any node. Therefore, at the end of iteration, all shortest paths of length are correct.
Thus, by mathematical induction, the shortest path distance to all nodes are correctly stored by the step and above, and hence Bellman-Ford correctly finds the shortest path distances.
Floyd-Warshall Algorithm
Pseudocode
Algorithm floydWarshall(G: graph):
V = number of vertices in graph G
dist = V * V array of minimum distances
for each vertex v
dist[v][v] = 0
for each edge (u,v):
dist[u][v] = weight(u,v)
for k from 1 to V:
for i from 1 to V:
for j from 1 to V:
if dist[i][j] > dist[i][k] + dist[k][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return dist
0/1 Knapsack Problem
Pseudocode
Algorithm knapsack(P: list, W: list, m: int, n: int):
// P is an array of profits e.g. [2, 3, 6, 9] for n = 4
// m is the capacity and n is the number of items
add 0 to the front of P and W
V = n + 1 by m + 1 matrix
for i from 0 to n:
for w from 0 to m:
if i = 0 or m = 0:
V[i, w] = 0
else:
V[i, w] = max(V[i - 1, w], V[i - 1, w - W[i]] + P[i])
return max(V)
If the items to keep are to be returned, replace return max(V)
with the following:
i = n and j = m
keep = list of 0s of length n + 1
while i>0 and j>0:
if V[i, j] = V[i - 1, j]:
// don't keep the item
keep[i] = 0
i = i - 1
else:
// keep the item
keep[i] = 1
i = i - 1
j = j - W[i]
remove first element from keep
return keep
Change-Making Problem
Pseudocode
Algorithm changeMaker(amount: int, coins: list):
let dp be array of size amount + 1
dp[0] = 0
for a from 1 to amount:
dp[a] = inf
for c in coins:
if a-c >= 0:
dp[a] = min(dp[a], dp[a-c] + 1)
if dp[amount] != inf:
return dp[amount]
else:
return -1
Fibonacci
Pseudocode
Algorithm fibonacci(n: int):
fib = [1, 1]
for i from 2 to n:
fib[i] = fib[i-1] + fib[i-1]
return fib[n]
Quicksort
Pseudocode
Algorithm quicksort(L: array<int>, a: int, b: int):
P = L[b]
i = a - 1
for j from a to b - 1:
if L[j] < P:
i = i + 1
Swap L[i] and L[j]
Swap L[b] and L[i + 1]
quicksort(L, a, i)
quicksort(L, i + 2, b)
Mergesort
Pseudocode
Algorithm mergesort(a: array):
let n be the side of a
if n = 1:
return a
m = n // 2
arr1 = a from 0 to m
arr2 = a from m + 1 to n
arr1 = mergesort(a)
arr2 = mergesort(b)
merge = []
while arr1 and arr2 both have elements:
if arr1[0] > arr2[0]:
merge.append(arr2[0])
remove first element from arr2
else:
merge.append(arr1[0])
remove first element from arr1
if arr1 is empty:
add the rest of arr2 to the end of merge
else:
add the rest of arr1 to the end of merge
return merge