--------------------------------------------------------------------------- COMP 731 - Data Struc & Algorithms - Lecture 22 - Friday, August 18, 2000 --------------------------------------------------------------------------- Today: o Dynamic Programming 1. Change making You are given coins of denominations 1=a_1, ..., a_c bhat. (eg, 1,3,8,17) for some c >=1. You are given a number n>=1. Your job is to make n bhat using as few coins as possible. eg: 1,3,8,17. want: 10 bhat: 8,1,1 24 bhat: 8,8,8 15 bhat: 8,3,3,1 NCoins(n) = 1 + min {NCoins(n-a_1), ..., NCoins(n-a_c)} Carefully include the base case: / 0 if n=0 | NCoins(n) = | infinity if n<0 | \ 1 + min {NCoins(n-a_1), ..., NCoins(n-a_c)} Code it without memoization. (Very inefficient.) const INFINITY = 0x7fffffff; int NCoins(int n) { if (n==0) return 0; if (n<0) return INFINITY; return 1 + min(NCoins(n-1), NCoins(n-3), NCoins(n-8), NCoins(n-17)) } n answer Time (SGI workstation, CC -O2) ---------------------------------------------- 10 3 .004 s 20 2 .005 s 30 5 .025 s 40 4 1.27 s 50 4 1.23 min 60 5 1.21 hr 70 3 days (est) 80 5.5 months (est) 100 1600 yrs (est) 200 7*10^20 yrs (est) Code it with memoization. const MAX 1000 int A[MAX+1]; for (int i=1; i<=MAX, i++) A[i] = 0; int NCoins(int n) { if (n==0) return 0; if (n<0) return INFINITY; if (n>MAX) error(); // return A[n] if it has if (A[n]) return A[n]; // already been defined return A[n] = 1 + min(NCoins(n-1), NCoins(n-3), NCoins(n-8), NCoins(n-17)); } n answer Time (SGI workstation, CC -O2) ---------------------------------------------- 10 3 .004 s 20 2 .004 s 30 5 .004 s 40 4 .004 s 50 4 .004 s 60 5 .004 s 70 6 .004 s 80 7 .004 s 100 8 .004 s 200 15 .005 s Code it with a table. int NCoins(int n) { if (n<0 or n>MAX) error(); int A[MAX]; A[0]=0; for (int i=0; i<=n; i++) { int n1 = n-1<0 ? 0:n-1, n3 = n-3<0 ? 0:n-3, n8 = n-8<0 ? 0:n-8, n17= n-17<0? 0:n-17 AA[i] = 1 + min(n1,n3,n8,n17); } return A[n]; } Example: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ---------------------------------------------------------- |0 | | | | | | | | | | | | | | | | | | | ---------------------------------------------------------- /|\ | to fill in the n-th entry in the table, look at entries n-1, n-3, n-8, n-17. (Some of these might not exist. If they don't exist, ignore them.) Choose the SMALLEST of these numbers and add one. Time: O(n) to fill in the table, since O(1) ti fill in each cell. Future examples will be more complicated, use two dimensional tables, require you to spend Theta(n) time to fill in cell, etc.. But same idea. Elements of dynamic programming ------------------------------- 1. optimal substructure: Optimal solutions to subproblems can be put together to solve the overall problem. (Same as greedy) 2. repeated subproblems: The same problem instances arise again and again, so solving them just once and saving the answers will save time. Approach: Understand the problem Write a recurrence relation Code it up. Modify to reconstruct the solution.