6 Dynamic Programming
6 Dynamic Programming
Dynamic Programming
• An algorithm design technique (like divide and
conquer)
2
DP - Two key ingredients
• Two key ingredients for an optimization problem
to be suitable for a dynamic-programming
solution:
4
Fibonacci numbers
F =0
0
F =1
1
F = F − + F − for i>1 .
i i 1 i 2
5
How to compute F10?
F8
F9
F7 ……
F10
F7
F8
F6
6
Dynamic Programming
• Applicable when subproblems are not independent
– Subproblems share subsubproblems
E.g.: Fibonacci numbers:
• Recurrence: F(n) = F(n-1) + F(n-2)
• Boundary conditions: F(1) = 0, F(2) = 1
• Compute: F(5) = 3, F(3) = 1, F(4) = 2
– A divide and conquer approach would repeatedly solve the
common subproblems
– Dynamic programming solves every subproblem just once and
stores the answer in a table
7
Tabular computation
• The tabular computation can avoid
recompuation.
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10
0 1 1 2 3 5 8 13 21 34 55
Result
8
Dynamic Programming Algorithm
1. Characterize the structure of an optimal
solution
2. Recursively define the value of an optimal
solution
3. Compute the value of an optimal solution in a
bottom-up fashion
4. Construct an optimal solution from computed
information
9
The Knapsack Problem
• The 0-1 knapsack problem
– A thief robbing a store finds n items: the i-th item is
worth vi dollars and weights wi pounds (vi, wi integers)
– The thief can only carry W pounds in his knapsack
– Items must be taken entirely or left behind
– Which items should the thief take to maximize the
value of his load?
• The fractional knapsack problem
– Similar to above
– The thief can take fractions of items
10
The 0-1 Knapsack Problem
• Thief has a knapsack of capacity W
• Goal:
– find xi such that for all xi = {0, 1}, i = 1, 2, .., n
∑ wixi ≤ W and
∑ xivi is maximum
11
0-1 Knapsack - Dynamic Programming
P(i, w) = P(i - 1, w)
13
0-1 Knapsack - Dynamic Programming
Item i was taken Item i was not taken
0: 1 w - wi w W
0 0 0 0 0 0 0 0 0 0 0 0
0 first
0 second
i-1 0
i 0
0
n 0 14
Example:
Max Capacity, W = 5
15
Max Capacity, W = 5 Item Weight Value
Example:
1 2 12
P(i, w) = max {vi + P(i - 1, w-wi), P(i - 1, w) }
2 1 10
w 3 3 20
0 1 2 3 4 5
4 2 15
0 0 0 0 0 0 0 P(1, 1) = P(~, 0) = 0 i wi vi
1 0 0 12 12 12 12 P(1, 2) = max{12+0, 0} = 12
i
2 0 10 12 22 22 22 P(1, 3) = max{12+0, 0} = 12
3 0 10 12 22 30 32 P(1, 4) = max{12+0, 0} = 12
4 0 10 15 25 30 37 P(1, 5) = max{12+0, 0} = 12
Calculate w-wi
• Start at P(n, W)
• When you go left-up ⇒ item i has been taken
• When you go straight up ⇒ item i has not been
taken
17
Dynamic Programming
Coin Changing Problem
Introduction
The Coin Change Problem is a classic dynamic programming problem. We're given a set
of coin denominations (e.g., [1, 2, 5]) and a total amount of money (e.g., 11).
The goal is to find the minimum number of coins required to make up that total amount.
● Example: For coins = [1, 2, 5] and amount = 11, the minimum number of coins is 3.
○ Solution: 5 + 5 + 1.
Why a "Greedy" Approach Doesn't Work
A simple, intuitive approach might be "greedy": always take the largest coin possible that is less than or equal to the remaining amount. Let's see
how this fails with a specific example.
● Coins: [1, 3, 4]
● Amount: 6
Greedy Approach:
Because the greedy approach failed to find the optimal solution, we need a more robust and systematic method, which is where dynamic
programming comes in.
2. Dynamic Programming Approach: The Logic
Dynamic programming solves problems by breaking them down into simpler, overlapping subproblems.
We build up a solution to the main problem by solving these smaller pieces first.
● We'll use a table (or array), let's call it dp, to store the minimum number of coins needed for
each amount from 0 up to our target amount.
● dp[i] will represent the minimum number of coins required to make the amount i.
● Our final answer will be dp[amount].
● We'll initialize dp[0] = 0 because it takes zero coins to make an amount of zero. All other dp
values will be initialized to a very large number (infinity) to represent that we haven't found a
solution yet.
3. The Recurrence Relation
The core of the dynamic programming solution is the recurrence relation. This formula tells us how to
calculate the value for each dp[i].
To find the minimum coins for an amount i, we can iterate through each coin denomination c we have.
If i >= c, we can potentially use coin c.
4. Final Answer: After the loops complete, dp[11] will hold the minimum number of coins. If dp[amount] is still
infinity, it means the amount cannot be made with the given coins.
Example
Total Amount: 10
Available Coins: 11 55 66 9
9
Available Coins: 11 55 66 99
Amount 0 11 2 3 4 5 6 7 8 9 10
Min. 1 2
Coins
Needed
Amount to make = 2
Coin Choice = 11 + 1 =2
Remainder = 11
Total Amount: 10
Available Coins: 11 55 66 99
Amount 0 11 2 3 4 5 6 7 8 9 10
Min. 1 2 3 4
Coins
Needed
1 5
Remainder = 44 Remainder = 0
Total Amount: 10
Available Coins: 11 55 66 99
Amou 0 1 2 3 4 5 6 7 8 9 10
nt
Min. 1 2 3 4 1 1 2 3 1 2
Coins
Need
ed
Problem 2. How to Find – Which Coins are selected?
Total Amount: 10
Available Coins: 1 5 6 9
● While you select minimum number of coins, Which coins did you select?
Total Amount: 10 Find- Min number of coins to make the total
Available Coins: 1 5 6 9
Total Amount, j
i coins 0 1 2 3 4 5 6 7 8 9 10
0 0 0 0 0 0 0 0 0 0 0 0 0
Available Coins
1 1 0 1 2 3 4 5 6 7 8 9 10
2 5 0 1 2 3 4 1
3 6 0
4 9 0
Min (5, 1+0)
𝑰𝒇 𝒋 ≥ 𝒄𝒐𝒊𝒏𝒔[𝒊], 𝒅𝒑 𝒊 𝒋 = 𝐦𝐢𝐧( 𝒅𝒑 𝒊 − 𝟏 𝒋 , 𝟏 + 𝒅𝒑 [𝒊][𝒋 − 𝒄𝒐𝒊𝒏𝒔 𝒊 )
𝒆𝒍𝒔𝒆, 𝒅𝒑 𝒊 𝒋 = 𝒅𝒑 𝒊 − 𝟏 𝒋
Total Amount: 10 Find- Min number of coins to make the total
Available Coins: 1 5 6 9
Total Amount
0 1 2 3 4 5 6 7 8 9 10
0 0 0 0 0 0 0 0 0 0 0
Available Coins
1 0 1 2 3 4 5 6 7 8 9 10
5 0 1 2 3 4 1 2 3 4 5 2
6 0 1 2 3 4 1 1 2 3 4 2
9 0 1 2 3 4 1 1 2 3 1 2
Coins Taken: 5 5 [ to make 10]
𝒆𝒍𝒔𝒆, 𝒅𝒑 𝒊 𝒋 = 𝒅𝒑 𝒊 − 𝟏 𝒋
Problem 3: Number of ways to get Total
Goal:
Coins: {1, 2, 5}
Given coins of certain denominations and a total amount, Total: 5
find how many distinct combinations of coins can sum
up to the total.
Ways:
•Input:
•coins[]: list of denominations 1. 1+1+1+1+1
•total: target amount 2. 1+1+1+2
3.1+2+2
•Output: Number of ways to make total 4.5
Example:
Coins = {1, 2, 5}, Total = 5 → 4 ways
Why Dynamic Programming?
Total Amount, j
0 1 2 3 4 5
Available Coins, i
00 1 0 0 0 0 0
11 1 1 1 1 1 1
22 1 1 2
33 1 1 2
𝒆𝒍𝒔𝒆, 𝒅𝒑 𝒊 𝒋 = 𝒅𝒑 𝒊 − 𝟏 𝒋
Coins = {1, 2, 3}, Total = 5
Find- Number of ways to get Total
Total Amount
0 1 2 3 4 5
Available Coins
00 1 0 0 0 0 0
11 1 1 1 1 1 1
22 1 1 2 2 3 3
33 1 1 2 3 4 5
𝒆𝒍𝒔𝒆, 𝒅𝒑 𝒊 𝒋 = 𝒅𝒑 𝒊 − 𝟏 𝒋
Dynamic Programming
Longest Common Subsequence (LCS)
Longest Common Subsequence (LCS)
39
Longest Common Subsequence
• Given two sequences
X = x1, x2, …, xm
Y = y1, y2, …, yn
find a maximum length common subsequence
(LCS) of X and Y
• E.g.:
X = A, B, C, B, D, A, B
• Subsequences of X:
– A subset of elements in the sequence taken in order
A, B, D, B, C, D, B, etc.
40
Example
X = A, B, C, B, D, A, B X = A, B, C, B, D, A, B
Y = B, D, C, A, B, A Y = B, D, C, A, B, A
41
Brute-Force Solution
• For every subsequence of X, check whether it’s a subsequence of
Y
42
LCS Algorithm
c[i − 1, j − 1] + 1 if x[i ] = y[ j ],
c[i, j ] =
max( c[i, j − 1], c[i − 1, j ]) otherwise
43
LCS recursive solution
c[i − 1, j − 1] + 1 if x[i ] = y[ j ],
c[i, j ] =
max( c[i, j − 1], c[i − 1, j ]) otherwise
• We start with i = j = 0 (empty substrings of x and y)
• Since X0 and Y0 are empty strings, their LCS is
always empty (i.e. c[0,0] = 0)
• LCS of empty string and any other string is empty,
so for every i and j: c[0, j] = c[i,0] = 0
44
LCS recursive solution
c[i − 1, j − 1] + 1 if x[i ] = y[ j ],
c[i, j ] =
max( c[i, j − 1], c[i − 1, j ]) otherwise
• When we calculate c[i,j], we consider two cases:
• First case: x[i]=y[j]:
– one more symbol in strings X and Y matches, so the length
of LCS Xi and Yj equals to the length of LCS of smaller
strings Xi-1 and Yi-1 , plus 1
45
LCS recursive solution
c[i − 1, j − 1] + 1 if x[i ] = y[ j ],
c[i, j ] =
max( c[i, j − 1], c[i − 1, j ]) otherwise
• Second case: x[i] != y[j]
– As symbols don’t match, our solution is not improved, and
the length of LCS(Xi , Yj) is the same as before (i.e.
maximum of LCS(Xi, Yj-1) and LCS(Xi-1,Yj)
• Second case: i
j-1 j
x[i] != y[j]
i-1 i
47
3. Computing the Length of the LCS
0 if i = 0 or j = 0
c[i, j] = c[i-1, j-1] + 1 if xi = yj
max(c[i, j-1], c[i-1, j]) if xi yj
0 1 2 n
yj: y1 y2 yn
0 xi 0 0 0 0 0 0
1 x1 0 first
2 x2 0 second
i
0
0
m xm 0
j
48
Additional Information
0 if i,j = 0 A matrix b[i, j]:
c[i, j] = c[i-1, j-1] + 1 if xi = yj • For a subproblem [i, j] it
max(c[i, j-1], c[i-1, j]) if xi yj tells us what choice was
made to obtain the
0 1 2 3 n
b & c: yj: A C D F optimal value
0 xi 0 0 0 0 0 0 • If xi = yj
1 A 0 b[i, j] = “ ”
2 B 0 • Else, if
c[i-1,j]
i c[i - 1, j] ≥ c[i, j-1]
3 C 0 c[i,j-1]
b[i, j] = “ ”
0
else
m D 0
b[i, j] = “ ”
j
49
Additional Information
0 if i,j = 0 A matrix b[i, j]:
c[i, j] = c[i-1, j-1] + 1 if xi = yj • For a subproblem [i, j] it
max(c[i, j-1], c[i-1, j]) if xi yj tells us what choice was
made to obtain the
0 1 2 3 4 n
b & c: yj: A C D E F optimal value
0 xi 0 0 0 0 0 0 • If xi = yj
1 A 0 b[i, j] = “ ”
2 B 0 • Else, if
i c[i - 1, j] ≥ c[i, j-1]
3 C 0 c[i-1,j-1]
b[i, j] = “ ”
4 E 0
else
m D 0
b[i, j] = “ ”
j
50
LCS-LENGTH(X, Y, m, n)
1. for i ← 1 to m
2. do c[i, 0] ← 0 The length of the LCS if one of the sequences
3. for j ← 0 to n is empty is zero
4. do c[0, j] ← 0
5. for i ← 1 to m
6. do for j ← 1 to n
7. do if xi = yj
8. then c[i, j] ← c[i - 1, j - 1] + 1 Case 1: xi = yj
9. b[i, j ] ← “ ”
10. else if c[i - 1, j] ≥ c[i, j - 1]
11. then c[i, j] ← c[i - 1, j]
12. b[i, j] ← “↑” Case 2: xi yj
13. else c[i, j] ← c[i, j - 1]
14. b[i, j] ← “←”
15. return c and b
Running time: (mn)
51
Example
0 if i = 0 or j = 0
X = A, B, C, B, D, A
c[i, j] = c[i-1, j-1] + 1 if xi = yj
Y = B, D, C, A, B, A
max(c[i, j-1], c[i-1, j]) if xi yj
0 1 2 3 4 5 6
If xi = yj yj B D C A B A
b[i, j] = “ ” 0 xi 0 0 0 0 0 0 0
1 A
Else if 0 0 0 0 1 1 1
c[i - 1, j] ≥ c[i, j-1] 2 B 0 1 1 1
1 2 2
b[i, j] = “ ” 3 C 0
1
1 2 2
2
2
else 4 B 0 1
1
2
2 3 3
b[i, j] = “ ” 5 D 0
1 2
2
2
3
3
6 A 0 1 2 2 3 3 4
7 B 0 1 2 2 3 4 4
52
4. Constructing a LCS
• Start at b[m, n] and follow the arrows
• When we encounter a “ “ in b[i, j] xi = yj is an element
of the LCS
0 1 2 3 4 5 6
yj B D C A B A
0 xi 0 0 0 0 0 0 0
1 A
0 0 0 0 1 1 1
2 B
0 1 1 1 1 2 2
3 C
0 1 1 2 2 2 2
4 B
0 1 1 2 2 3 3
5 D
0 1 2 2 2 3 3
6 A 0 1 2 2 3 3 4
7 B 0 1 2 2 3 4 4
53
PRINT-LCS(b, X, i, j)
1. if i = 0 or j = 0 Running time: (m + n)
2. then return
3. if b[i, j] = “ ”
4. then PRINT-LCS(b, X, i - 1, j - 1)
5. print xi
6. elseif b[i, j] = “↑”
7. then PRINT-LCS(b, X, i - 1, j)
8. else PRINT-LCS(b, X, i, j - 1)
57
Longest increasing subsequence(LIS)
58
A naive approach for LIS
• Let L[i] be the length of a longest increasing
subsequence ending at position i.
L[i] = 1 + max j = 0..i-1{L[j] | aj < ai}
(use a dummy a0 = minimum, and L[0]=0)
Index 0 1 2 3 4 5 6 7 8 9 10
Input 0 9 2 5 3 7 11 8 10 13 6
Length
Prev
Input 0 9 2 5 3 7 11 8 10 13 6
Length 0 1 1 2 2 3 4 4 5 6 3
Prev -1 0 0 2 2 4 5 5 7 8 4