2.30 (a) Assume the pigeonhole principle is false. That is, for some n, there is a way to put n+1 pigeons in n holes so that every hole has at most one pigeon. Letting the holes be numbered 1,2,...,n, for i = 1,...,n, let pi be the number of pigeons in hole number i. Then the total number of pigeons is p1 + ... + pn. But each pi <= 1, so p1 + ... + pn <= 1 + ... + 1 (1 added to itself n times) = n That is, the total number of pigeons is <= n, contradiction. (b) Base case: n = 1. Then there are two pigeons and one hole, so we're done. Induction step: assume the pigeonhole principle holds for n pigeons and n-1 holes, and show it holds for n+1 pigeons and n holes. Consider the last hole. Either it has at least two pigeons or it doesn't. If it has at least two pigeons, we're done. If it doesn't, then it has at most one pigeon. That means that at least n pigeons are in the first n-1 holes. Using our induction assumption, one of these holes must contain at least two pigeons, so we're done in this case. 2.33 Unwinding: T(n) = 2T(n-1) + 1 = 2[2T(n-2) + 1] + 1 = 4T(n-2) + 2 + 1 ... = (2#i)T(n-i) + 2#(i-1) + ... + 2 + 1 ... = 2#(n-1) + 2#(n-2) + ... + 2 + 1 = 2#n - 1 by equation (2.7) (This is not a proof, of course.) Use induction on n to prove T(n) = 2#n - 1: Base: N = 1: T(1) = 1 by definition 2#1 - 1 = 1 Induction: assume T(n-1) = 2#(n-1) - 1. T(n) = 2T(n-1) + 1 by definition = 2[2#(n-1) - 1] + 1 by induction assumption = 2#n - 1 3.1 When n=0, 10n, 5nlogn, and 2n#2 are most efficient. When n=1, 5nlogn is most efficient. When n=2,3, n! is most efficient. When n=4,5, 2#n is most efficient. When n>5, 10n is most efficient. 3.3 2 log_3 n log_2 n n#(2/3) 20n 4n#2 3#n n! 3.4 (a) Let m be the number of inputs that a machine that is 64 times faster can process in the same time that the old machine takes to process n inputs. Then T(m)/64 = T(n), or 3*2#(m-6) = 3*2#n. Solving for m, m = n+6. (b) This time, the equation is m#2/64 = n#2, so m = 8n. (c) This time the equation is 8m/64 = 8n, so m = 64n. 3.5 This uses the same ideas as 3.4. The four cases are: n = m/100, so m = 100n n#2 = m#2/100, so m = 10n n#3 = m#3/100, so m = 4.6n (approx.), because the cube root of 100 is 4.6 (approx.) 2#n = 2#m/100, so m = n + 6.6 (approx.), because the base 2 log of 100 is 6.6 (approx.) 3.11 (a) log n#2 = 2log n, so f(n) is in Theta(g(n)). (b) f(n) = n#(1/2), g(n) = 2log n, and g(n)/f(n) is asymptotic to 0 (using calculus: compare the derivatives of f(n) and g(n) or just use l'Hospital's rule), so f(n) is in Omega(g(n)) but not in O(g(n)). (c) g(n)/f(n) = 1/log n, which is asymptotic to 0, so f(n) is in Omega(g(n)) but not in O(g(n)). (d) Same reasoning as in (b) and (c). (e) Same reasoning as in (b), (c), and (d). (f) f(n)/g(n) = 2/log n, which is asymptotic to 0, so f(n) is in O(g(n)) but not in Omega(g(n)). (g)Both f(n) and g(n) are constants, i.e., they are Theta(1), so f(n) is in Theta(g(n)). (h) Same reasoning as in (b), (c), (d), and (e). (i) Same reasoning as in (b), (c), (d), (e), and (h). (j) f(n)/g(n) = (2/3)#n, which is asymptotic to 0, so f(n) is in O(g(n)), but not in Omega(g(n)). (k) Same reasoning as in (j). 3.12 (a) Theta(1). (b) Theta(n) because the inner loop takes Theta(n) but the outer loop is executed only Theta(1) times. (c) Theta(n#2) (d) Theta(n#2) (e) Theta(n log n) (f) Theta(n log n) (g) Theta(n#2 log n) because the inner loop takes Theta(n) and the call to sort takes Theta(nlog n). Therefore the total time of one execution of the outer loop is Theta(n + nlog n) = Theta(nlog n) by rule 3 The outer loop is executed Theta(n) times, so the total time is Theta(n#2 log n) by rule 4. (h) Theta(n#2) because each execution of the inner loop takes Theta(j), where j is the index such that A[j] = i. Since A is a permutation of 0,...,n-1, each of the numbers 0,...,n-1 is used once as the index j such that A[j] = i. Therefore the total cost of the outer loop is Theta(0) + Theta(1) + ... + Theta(n-1) = Theta(n#2) by equation (2.1). (i) This is a weird one because the run time is not asymptotic to any algebraic function. But we can answer it this way. Let f(n) be defined as f(n) = n if n is even = 1 if n is odd Then the (average) run time is Theta(f(n)). More to the point, The best case time is in Omega(1) and the worst case time is in O(n).