Algorithm Design CS 515 Fall 2015 Sample Final Exam Solutions Copyright c 2015 Andrew Klapper. All rights reserved. 1. For the functions satisfying the following three recurrences, determine which is the fastest growing and which is the slowest growing (a) T (n) = 2T (n 1), T (1) = 5. (b) S(n) = S(n 1) + log(n), S(1) = 17. (c) R(n) = 3R( n/2 ) + 4, R(1) = 11. We have T (n) = 5 2 n 1. We have S(n) = log(n) + log(n 1) + + log(2) +17 log(n!) + 17 Θ(n log(n)) and similarly S(n) log(n!) n + 17. By the master theorem for divide and conquer recurrences, R(n) Θ(n log 2 (3) ). Thus S(n) o(r(n)) and R(n) o(t (n)). 2. Prove that log 2 (n) O(2 n ). It suffices to show that log(n) O(2 n/2 ). By L Hospital s rule, log(n) lim n 2 = lim n/2 n (1/n) log(e) 2 n/2 (n 1/2 /4) ln(2) = lim n log(e) 2 n/2 (n 1/2 /4) ln(2) = 0. 3. Give a proof by invariants that the following algorithm correctly searches a sorted list for element z. Search(X,n,z) { i = 0 j = n-1 while (i < j) { k = (i+j)/2 if (X[k] = z) return(k) if (X[k] < z) i = k+1 X[0],, X[n 1]
else j = k-1 if (X[i] = z) return(i) else return(failure) Assumption: X[1] X[2] X[n 1] Correctness: P: If there is a t so that X[t] = z, then the algorithm returns a t with X[t] = z. Invariant: R: If there is a t {0, 1,, n 1 so that X[t] = z, then there is a t {i,, j so that X[t] = z. R is true initially since i = 0 and j = n 1. Assume R at the start of an iteration. If X[k] = z, then the loop never repeats. Suppose there is a t {0, 1,, n 1. By R we may assume i t j. If X[k] < z, then any t with X[t] = z satisfies k < t, so there is a t {k + 1,, j with X[t] = z. If X[k] > z, then any t with X[t] = z satisfies k > j, so there is a t {i,, k 1 with X[t] = z. Thus R holds at the start of the next iteration. If the algorithm returns at either return statement, it is returning a correct value. Suppose the loop terminates without having returned, R holds, and there is a t so that X[t] = z. Then there is a t so that X[t] = z and i t j i, so t = i and i will be returned. The loop eventually returns or terminates since j i + 1 decreases at each iteration. 4. Let H be an array containing a min-heap with n elements (the smallest element is at the top, and the children of H[i] are H[2i] and H[2i + 1]). Give pseudocode for an efficient algorithm for deleting the smallest element from H. What is the worst case time complexity of your algorithm? Move the last element to H[1] and then bubble it down until it s smaller that than both its children. Always swap with the smaller child. x = H[1] H[1] = H[n] n = n-1 k = 1 while (2k+1 <= n and H[k] > min(h[2k],h[2k+1])) { if (H[2k] < H[2k+1]) j=2k
else j = 2k+1 swap(h[k],h[j]) k = j if (2k <= n and H[k] > H[2k]) swap(h[k],h[2k]) return(x) Time: the number of iterations is at most the height of the heap, which is at most log(n). So time is O(log(n)). 5. (a) Find a sharp upper bound on the height of a 2-3 tree with n nodes. Every internal node has at least 2 children, and every leaf is at the same depth, so if the height is h there are at least 1 + 2 + 2 2 + + 2 h = 2 h+1 1 nodes. That is, 2 h+1 1 n, so h log(n + 1) 1. (b) Compare the performance of search trees, red-black trees, B-trees, or other such structures under various mixes of the basic operations (search, insert, delete). There are lots of possible variants of this and lots of different answers. The main idea is to discuss time complexity of the various operations, how much extra memory is needed, ease of programming, situations where one or another structure is preferred, and so on. 6. Describe an efficient algorithm to count the connected components in an undirected graph. Analyze the complexity of your algorithm. It should run in linear time. Use a counter c to count the components, initialized to 0. While possible, pick an unvisited node u and do a DFS from u. After each DFS, increment c. The final value of c is the number of connected components. Time is O(n + e) since this is the time of DFS. 7. Let G = (V, E) be a directed graph with edge capacities c(u, v) 0, a sink s, and a source t. Prove that if f is a flow on G and f is a flow on the residual graph G f, then the function g defined by g(u, v) = f(u, v) + f (u, v) is a flow on G. The symmetry and conservation laws are linear equations so are preserved by addition of the flows. To prove the capacity bound, for every edge e we have f (e) c f (e) = c(e) f(e). Thus f(e) + f (e) f(e) + c(e) f(e) = c(e). 8. Dynamic programming
Let S = s 1 s 2 s n be a string over the alphabet {a, b and consider the two operations Insert (insert a symbol in S) and Delete (delete a symbol from S). An ID-edit sequence is a sequence of Inserts and Deletes. If S = s 1 s n and T = t 1 t k are two strings, then MinID(S, T ) is the length of the shortest ID-edit sequence that changes S into T. For 0 i n let S(i) = s 1 s 2 s i. (a) Express M inid(s(i), T (j)) in terms of M inid of shorter strings. (Hint: consider separately the cases s i = t j and s i t j.) If s i = t j, then MinID(S(i), T (j)) = MinID(S(i 1), T (j 1)). If s i t j, then either MinID(S(i), T (j)) = 1 + MinID(S(i 1), T (j)) (delete the last element of S(i)) or MinID(S(i), T (j)) = 1 + MinID(S(i), T (j 1)) (insert the last symbol of T (j)). That is: MinID(S(i), T (j) = MinID(S(i { 1), T (j 1)) MinID(S(i 1), T (j)) (delete end of S(i)) or 1 + min MinID(S(i), T (j 1)) (insert end of T (j)) if s i = t j if s i t j. (b) Using dynamic programming, give an efficient algorithm that computes M inid. Give pseudocode and analyze the worst case time complexity. 9. Algebra MinID(S,n,T,k) { for (i=0 to n) M[i,0] = i for (j=1 to k) M[0,j] = j for (i=1 to n) for (j=1 to k) if (S[i] = T[j]) M[i,j] = M[i-1,j-1] else M[i,j] = 1 + minimum(m[i,j-1],m[i-1,j]) return(m[n,k]) Two nested loops take time Θ((n + 1)(k + 1)).
(a) Describe an efficient algorithm which, given integers a, k, m with 0 a < m and k 0, computes a k (mod m). Analyze the complexity of the algorithm in terms of the time M(t) required to multiply two t bit integers. Let k = r i=0 k i2 i with k i {0, 1. We want to compute z i = 2 2i (mod m) for i r and then a k (mod m) = z i. k i =1 z = 2 b = 1 while (k > 0) { if (k mod 2 = 1) b = bz mod m z = zz mod m return(b) The loop iterates r = O(log(k)) times, and the body take M(log(m)) time, so the whole thing is O(log(k)M(log(m))). (b) How can the Extended Euclidean Algorithm be used to find the inverse of an integer a modulo an integer m? Given a, m Z, the EEA finds s and t so sa + tm = gcd(a, m). If the gcd is 1, then sa 1 (mod m), so s is the inverse of a modulo m. 10. Intractibility (a) Prove that if K and L are in NP, then the concatenation KL is in NP. Suppose we are given NP algorithms A, B that recognize K, L, respectively. Then to recognize KL, input x = x 1 x 2 x n ; guess 0 i n; let y = x 1 x i and z = x i+1 x n ; run A on y and B on z; accept iff both accept. (b) Let L be NP-complete and let K be in NP. Let J = {(x, 0) : x L {(y, 1) : y K. Prove that J is NP-complete. J is in NP: On input (x, 0), run an NP decider for L on input x. On input (y, 1), run an NP decider for K on input y. J is NP-hard: Let M NP. Then M m p L by some polynomial time computable function f. Thus x M iff f(x) L. Define g(x) = (f(x), 0). Then x M iff g(x) J, and g is poynomial time computable.