Lab 6. Dynamic Programming_Instructions
Lab 6. Dynamic Programming_Instructions
❖ Overlapping Subproblems
A problem exhibits overlapping subproblems if the same subproblem appears
multiple times in the computation. If these subproblems are not stored,
redundant computations can lead to inefficiency.
Examples:
● In the Fibonacci sequence, a naive recursive approach recalculates the
same Fibonacci numbers multiple times, resulting in a time complexity of
O(2n). Using Dynamic Programming to store results can reduce the
complexity to O(n).
● By storing the results of subproblems in a table (array or other data
structures), we can retrieve previously computed values without redundant
calculations, significantly improving efficiency.
1.3. Comparison of Top-down and Bottom-up Approaches
- Avoids recursion
overhead, often more
- State transition can be
efficiently.
difficult to define.
Iteratively builds - Fast due to direct
- If many conditions are
Bottom-up the solution from access to the table of
required, code can be
(Tabulation) smaller results of previously
complex.
subproblems. solved subproblems.
- All entries must be filled
- Works well for
sequentially.
problems with clear
state transitions.
Length i 1 2 3 4 5 6 7 8 9 10
Price pi 1 5 8 9 10 17 17 20 24 30
(1)
(2)
For our sample problem, we can determine the optimal revenue figures ri, for i =
1; 2; … ; 10, by inspection, with the corresponding optimal decompositions:
r1 = 1 from solution 1 = 1 (no cuts)
r2 = 5 from solution 2 = 2 (no cuts)
r3 = 8 from solution 3 = 3 (no cuts)
r4 = 10 from solution 4 = 2 + 2
r5 = 13 from solution 5 = 2 + 3
r6 = 17 from solution 6 = 6
r7 = 18 from solution 7 = 1 + 6 or 7 = 2 + 2 + 3
r8 = 22 from solution 8 = 2 + 6
r9 = 25 from solution 9 = 3 + 6
r10 = 30 from solution 10 = 10
We view a decomposition as consisting of a first piece of length i cut off the left-
hand end, and then a right-hand remainder of length n - i. Only the remainder,
and not the first piece, may be further divided. We may view every decomposition
of a length-n rod in this way: as a first piece followed by some decomposition of
the remainder. When doing so, we can couch the solution with no cuts at all as
saying that the first piece has size i = n and revenue p n and that the remainder
has size 0 with corresponding revenue r0 = 0. We can frame the values rn for n >=
1 in terms of optimal revenues from shorter rods:
(3)
Recursive top-down implementation
The following procedure implements the computation implicit in equation (3) in a
straightforward, top-down, recursive manner.
if (n == 0)
q = 0;
else
q = -1;
int main() {
int price[] = {0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30};
int n = 10; // Rod length
1 10 60
2 20 100
3 30 120
0 0 0 0 0 0 0
1 0 60 60 60 60 60
KS-MEMO(n, W, memo, w, v)
1. If W == 0 or n == 0
return 0
2. If memo[n][W] is not -1
return memo[n][W]
3. If w[n] > W
result = KS-MEMO(n-1, W, memo) // Cannot include item n
4. Else
result = max(
KS-MEMO(n-1, W, memo,w,v), // Exclude item n
v[n] + KS-MEMO(n-1, W - w[n], memo,w,v) // Include item n
)
5. memo[n][W] = result
6. return result
Bottom - up approach
Reconstructing a solution
TRACEBACK(n, W, memo, w, v)
1. items = [] // Stores selected items
2. while n > 0 and W > 0:
3. If memo[n][W] == memo[n-1][W]:
4. // Item n was NOT included, move to previous item
5. n=n-1
6. Else:
7. // Item n was included, add to list
8. items.append(n)
9. W = W - w[n] // Reduce remaining capacity
10. n=n-1
11. return items // List of selected items
0 A B C D E
0 0 0 0 0 0 0
A 0 1 1 1 1 1
C 0 1 1 2 2 2
D 0 1 1 2 3 3
E 0 1 2 2 3 4
LCS-recur(X, Y, M, i, j)
5. if (i == 0 or j == 0) return 0 // Base case: empty sequence
6. if (M[i, j] != -1) return M[i, j] // Return if already computed
7. if (X[i] == Y[j]) // Match found (1-based index)
8. M[i, j] = LCS-recur(X, Y, M, i-1, j-1) + 1
9. else
10. M[i, j] = max(LCS-recur(X, Y, M, i-1, j), LCS-recur(X, Y, M, i, j-1))
11. return M[i, j]
Bottom - up approach
LCS-BottomUp(X, Y)
1. n = length(X) // Get length of X
2. m = length(Y) // Get length of Y
3. Create table M[0:n, 0:m] initialized with 0 // DP table
4. for i = 1 to n
5. for j = 1 to m
6. if X[i] == Y[j] // Match found
7. M[i, j] = M[i-1, j-1] + 1
8. else
9. M[i, j] = max(M[i-1, j], M[i, j-1])
10. return M[n, m] // LCS length
Reconstructing a solution
LCS-Traceback(X, Y, M)
1. i = length(X)
2. j = length(Y)
3. LCS_sequence = "" // Empty string to store LCS
4. while i > 0 and j > 0
5. if X[i] == Y[j] // Match found, move diagonally
6. Prepend X[i] to LCS_sequence
7. i=i-1
8. j=j-1
9. else if M[i-1, j] > M[i, j-1] // Move up