CPSC 411 Design and Analysis of Algorithms Set 5: Dynamic Programming Prof. Jennifer Welch Spring 2011 CPSC 411, Spring 2011: Set 5 1
2 Drawback of Divide & Conquer Sometimes can be inefficient Fibonacci numbers: F 0 = 0 F 1 = 1 F n = F n-1 + F n-2 for n > 1 Sequence is 0, 1, 1, 2, 3, 5, 8, 13, …
CPSC 411, Spring 2011: Set 53 Computing Fibonacci Numbers Obvious recursive algorithm: Fib(n): if n = 0 or 1 then return n else return (F(n-1) + Fib(n-2))
CPSC 411, Spring 2011: Set 54 Recursion Tree for Fib(5) Fib(5) Fib(4) Fib(3) Fib(2) Fib(1) Fib(2)Fib(1) Fib(0)Fib(1)Fib(0) Fib(1)Fib(0)
CPSC 411, Spring 2011: Set 55 How Many Recursive Calls? If all leaves had the same depth, then there would be about 2 n recursive calls. But this is over-counting. However with more careful counting it can be shown that it is ((1.6) n ) Still exponential!
CPSC 411, Spring 2011: Set 56 Save Work Wasteful approach - repeat work unnecessarily Fib(2) is computed three times Instead, compute Fib(2) once, store result in a table, and access it when needed
CPSC 411, Spring 2011: Set 57 More Efficient Recursive Alg F[0] := 0; F[1] := 1; F[n] := Fib(n); Fib(n): if n = 0 or 1 then return F[n] if F[n-1] = NIL then F[n-1] := Fib(n-1) if F[n-2] = NIL then F[n-2] := Fib(n-2) return (F[n-1] + F[n-2]) computes each F[i] only once
CPSC 411, Spring 2011: Set Example of Memoized Fib NIL F Fib(5) Fib(4) Fib(3) Fib(2) returns 0+1 = 1fills in F[2] with 1, returns 1+1 = 2 fills in F[3] with 2, returns 2+1 = 3 fills in F[4] with 3, returns 3+2 = 5
CPSC 411, Spring 2011: Set 59 Get Rid of the Recursion Recursion adds overhead extra time for function calls extra space to store information on the runtime stack about each currently active function call Avoid the recursion overhead by filling in the table entries bottom up, instead of top down.
CPSC 411, Spring 2011: Set 510 Subproblem Dependencies Figure out which subproblems rely on which other subproblems Example: F 0 F 1 F 2 F 3 … F n-2 F n-1 F n
CPSC 411, Spring 2011: Set 511 Order for Computing Subproblems Then figure out an order for computing the subproblems that respects the dependencies: when you are solving a subproblem, you have already solved all the subproblems on which it depends Example: Just solve them in the order F 0, F 1, F 2, F 3, …
CPSC 411, Spring 2011: Set 512 DP Solution for Fibonacci Fib(n): F[0] := 0; F[1] := 1; for i := 2 to n do F[i] := F[i-1] + F[i-2] return F[n] Can perform application-specific optimizations e.g., save space by only keeping last two numbers computed
CPSC 411, Spring 2011: Set 513 Matrix Chain Order Problem Multiplying non-square matrices: A is n x m, B is m x p AB is n x p whose (i, j ) entry is ∑a ik b k j Computing AB takes nmp scalar multiplications and n(m-1)p scalar additions (using basic algorithm). Suppose we have a sequence of matrices to multiply. What is the best order? must be equal
CPSC 411, Spring 2011: Set 514 Why Order Matters Suppose we have 4 matrices: A, 30 x 1 B, 1 x 40 C, 40 x 10 D, 10 x 25 ((AB)(CD)) : requires 41,200 mults. (A((BC)D)) : requires 1400 mults.
CPSC 411, Spring 2011: Set 515 Matrix Chain Order Problem Given matrices A 1, A 2, …, A n, where A i is d i-1 x d i : [1] What is minimum number of scalar mults required to compute A 1 · A 2 ·… · A n ? [2] What order of matrix multiplications achieves this minimum? Focus on [1]; see textbook for how to do [2]
CPSC 411, Spring 2011: Set 516 A Possible Solution Try all possibilities and choose the best one. Drawback is there are too many of them (exponential in the number of matrices to be multiplied) Need to be more clever - try dynamic programming!
CPSC 411, Spring 2011: Set 517 Step 1: Develop a Recursive Solution Define M(i, j ) to be the minimum number of mults. needed to compute A i · A i+1 ·… · A j Goal: Find M(1,n). Basis: M(i,i) = 0. Recursion: How to define M(i, j ) recursively?
CPSC 411, Spring 2011: Set 518 Defining M(i, j ) Recursively Consider all possible ways to split A i through A j into two pieces. Compare the costs of all these splits: best case cost for computing the product of the two pieces plus the cost of multiplying the two products Take the best one M(i,j) = min k (M(i,k) + M(k+1, j ) + d i-1 d k d j )
CPSC 411, Spring 2011: Set 519 Defining M(i, j ) Recursively (A i ·…· A k )·(A k+1 ·… · A j ) P1P1 P2P2 minimum cost to compute P 1 is M(i,k) minimum cost to compute P 2 is M(k+1,j) cost to compute P 1 · P 2 is d i-1 d k d j
CPSC 411, Spring 2011: Set 520 Step 2: Find Dependencies Among Subproblems n/a GOAL! M: computing the red square requires the blue ones: to the left and below.
CPSC 411, Spring 2011: Set 521 Defining the Dependencies Computing M(i, j ) uses everything in same row to the left: M(i,i), M(i,i+1), …, M(i, j -1) and everything in same column below: M(i, j ), M(i+1, j ),…,M( j, j )
CPSC 411, Spring 2011: Set 522 Step 3: Identify Order for Solving Subproblems Recall the dependencies between subproblems just found Solve the subproblems (i.e., fill in the table entries) this way: go along the diagonal start just above the main diagonal end in the upper right corner (goal)
CPSC 411, Spring 2011: Set 523 Order for Solving Subproblems n/a M:
CPSC 411, Spring 2011: Set 524 Pseudocode for i := 1 to n do M[i,i] := 0 for d := 1 to n-1 do // diagonals for i := 1 to n-d to // rows w/ an entry on d-th diagonal j := i + d // column corresponding to row i on d-th diagonal M[i,j] := infinity for k := 1 to j-1 to M[i,j] := min(M[i,j], M[i,k]+M[k+1,j]+d i-1 d k d j ) endfor running time O(n 3 ) pay attention here to remember actual sequence of mults.
CPSC 411, Spring 2011: Set 525 Example M: n/a n/a 010,000 4n/a 0 1: A is 30x1 2: B is 1x40 3: C is 40x10 4: D is 10x25
CPSC 411, Spring 2011: Set 526 Keeping Track of the Order It's fine to know the cost of the cheapest order, but what is that cheapest order? Keep another array S and update it when computing the minimum cost in the inner loop After M and S have been filled in, then call a recursive algorithm on S to print out the actual order
CPSC 411, Spring 2011: Set 527 Modified Pseudocode for i := 1 to n do M[i,i] := 0 for d := 1 to n-1 do // diagonals for i := 1 to n-d to // rows w/ an entry on d-th diagonal j := i + d // column corresponding to row i on d-th diagonal M[i,j] := infinity for k := 1 to j-1 to M[i,j] := min(M[i,j], M[i,k]+M[k+1,j]+d i-1 d k d j ) if previous line changed value of M[i,j] then S[i,j] := k endfor keep track of cheapest split point found so far: between A k and A k+1
CPSC 411, Spring 2011: Set 528 Example M: n/a n/a 010,000 4n/a 0 1: A is 30x1 2: B is 1x40 3: C is 40x10 4: D is 10x S:
CPSC 411, Spring 2011: Set 529 Using S to Print Best Ordering Call Print(S,1,n) to get the entire ordering. Print(S,i, j ): if i = j then output "A" + i //+ is string concat else k := S[i, j ] output "(" + Print(S,i,k) + Print(S,k+1, j ) + ")"
CPSC 411, Spring 2011: Set 530 Example S: 124 1n/a <<draw recursion tree on board>>