Dynamic Programming Paradigm: - For optimization problems that satisfy the following properties: . "simple subproblems": subproblems can be characterized precisely using a constant number of parameters (usually numerical indices); . "subproblem optimality": an optimal solution to the problem can be obtained from optimal solutions to subproblems; . "subproblem overlap": smaller subproblems are repeated many times as part of larger problems. - Step 0: Describe recursive structure of problem: how problem can be decomposed into simple subproblems and how global optimal solution relates to optimal solutions to these subproblems. - Step 1: Define an array indexed by the parameters that define subproblems, to store the optimal value for each subproblem (make sure one of the "sub"problems actually equals the whole problem). - Step 2: Based on the recursive structure of the problem, describe a recurrence relation satisfied by the array values from step 1 (including degenerate or base cases). - Step 3: Write iterative algorithm to compute values in the array, in a bottom-up fashion, following recurrence from step 2. - Step 4: Use computed array values to figure out actual solution that achieves best value (generally, describe how to modify algorithm from step 3 to be able to find answer). Interval scheduling with profits: [6.1] - Just like activity (interval) scheduling but each activity (interval) has a "profit" and we want schedule with maximum profit. More precisely: Input: Activities (s_1,f_1,w_1), ..., (s_n,f_n,w_n) where s_i = start time, f_i = finish time, w_i = profit. Output: Subset of activities S subset {1,2,...,n} such that no activities in S overlap and profit(S) is maximal. - Greedy doesn't work, no matter how we sort. - Step 0: Subproblems consist of subsets of activities to choose from, but no easy way to characterize these using constant number of parameters. Trick: Sort activities by finish time, as before (f_1 <= ... <= f_n). Consider optimal schedule S, and last activity scheduled in S, say k. Then k must be larger than index of all other jobs scheduled (because of sorting order) and rest of schedule must consist of optimal way to schedule the other activities. - Step 1: Define array A[i] = max profit from scheduling activities 1,2,...,i - Step 2: Write recurrence A[0] = 0 A[i] = max( A[i-1], w_i + A[j] ) where j = largest index <= i-1 such that f_j <= s_i because either job i is not required to get an optimal schedule (in which case A[i] = A[i-1]) or job i is required (in which case A[i] = w_i + A[j]). - Step 3: Bottom-up algorithm A[0] := 0 for i := 1 to n: A[i] := A[i-1] find largest j <= i-1 such that f_j <= s_i if j > 0 and A[i] < w_i + A[j]: A[i] := w_i + A[j] - Step 4: Compute optimal answer S := {} i := n while i > 0: if A[i] = A[i-1]: // don't schedule job i i := i - 1 else: // schedule job i S := S U {i} i := largest j <= i-1 such that f_j <= s_i return S - Runtime? O(n^2) (for each job, may have to look at all previous ones to find j) -- if information about the values of j is precomputed, then only O(n). If the jobs are sorted, the pre-computation may be done in O(n).