CSE 207
Algorithms
Dynamic Programming
Dynamic Programming
• An algorithm design technique (like divide and
conquer)
• Divide and conquer
– Partition the problem into independent subproblems
– Solve the subproblems recursively
– Combine the solutions to solve the original problem
2
DP - Two key ingredients
• Two key ingredients for an optimization problem
to be suitable for a dynamic-programming
solution:
1. optimal substructures 2. overlapping subproblems
Subproblems are dependent.
Each substructure is (otherwise, a divide-and-
optimal. conquer approach is the
(Principle of optimality) choice.) 3
Three basic components
• The development of a dynamic-programming
algorithm has three basic components:
– The recurrence relation (for defining the value of an
optimal solution);
– The tabular computation (for computing the value of
an optimal solution);
– The traceback (for delivering an optimal solution).
4
Fibonacci numbers
The Fibonacci numbers are defined by the
following recurrence:
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
10
– The thief can take fractions of items
The 0-1 Knapsack Problem
• Thief has a knapsack of capacity W
• There are n items: for i-th item value vi and
weight wi
• Goal:
– find xi such that for all xi = {0, 1}, i = 1, 2, .., n
wixi W and
xivi is maximum
11
0-1 Knapsack - Greedy Strategy
• E.g.:
Item 3 30 $120
Item 2 50 50 50 +
20 $100
Item 1 30
20 + 20 $100
10 10 $60
$60 $100 $120 $160 $220
$6/pound $5/pound $4/pound
• None of the solutions involving the greedy
choice (item 1) leads to an optimal solution
– The greedy choice property does not hold
12
0-1 Knapsack - Dynamic Programming
• P(i, w) – the maximum profit that can be
obtained from items 1 to i, if the
knapsack has size w
• Case 1: thief takes item i
P(i, w)vi=+ P(i - 1, w-wi)
• Case 2: thief does not take item i
P(i, w)P(i
= - 1, w)
13
0-1 Knapsack - Dynamic Programming
Item i was taken Item i was not taken
P(i, w) = max {vi + P(i - 1, w-wi), P(i - 1, w) }
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
W = 5 Item Weight Value
Example:
P(i, w) = max {vi + P(i - 1, w-wi), P(i - 1,1 2 12
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, 1) = 0
1 0 0 12 12 12 12 P(1, 2) = max{12+0, 0} = 12
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
P(2, 1)= max{10+0, 0} = 10 P(3, 1)= P(2,1) = 10 P(4, 1)= P(3,1) = 10
P(2, 2)= max{10+0, 12} = 12 P(3, 2)= P(2,2) = 12 P(4, 2)= max{15+0, 12} = 15
P(2, 3)= max{10+12, 12} = 22 P(3, 3)= max{20+0, 22}=22 P(4, 3)= max{15+10, 22}=25
P(2, 4)= max{10+12, 12} = 22 P(3, 4)= max{20+10,22}=30 P(4, 4)= max{15+12, 30}=30
P(2, 5)= max{10+12, 12} = 22 P(3, 5)= max{20+12,22}=32 P(4, 5)= max{15+22, 32}=37
15
Reconstructing the Optimal Solution
0 1 2 3 4 5
0 0 0 0 0 0 0 • Item 4
1 0 0 12 12 12 12
• Item 2
2 0 10 12 22 22 22
3 0 10 12 22 30 32 • Item 1
4 0 10 15 25 30 37
• 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
16
Knapsack Problem by DP (pseudocode)
18
Longest Common Subsequence (LCS)
Application: comparison of two DNA strings
Ex: X= {A B C B D A B }, Y= {B D C A B A}
Longest Common Subsequence:
X = A B C B D A B
Y = B D C A B A
Brute force algorithm would compare each
subsequence of X with the symbols in Y
19
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.
20
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
B, C, B, A and B, D, A, B are longest common
subsequences of X and Y (length = 4)
B, C, A, however is not a LCS of X and Y
21
Brute-Force Solution
• For every subsequence of X, check whether it’s
a subsequence of Y
• There are 2m subsequences of X to check
• Each subsequence takes (n) time to check
– scan Y for first letter, from there scan for second, and
so on
• Running time: (n2m)
22
LCS Algorithm
• First we’ll find the length of LCS. Later we’ll modify
the algorithm to find LCS itself.
• Define Xi, Yj to be the prefixes of X and Y of length i
and j respectively
• Define c[i,j] to be the length of LCS of Xi and Yj
• Then the length of LCS of X and Y will be c[m,n]
c[i 1, j 1] 1 if x[i ] y[ j ],
c[i, j ]
max(c[i, j 1], c[i 1, j ]) otherwise
23
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
24
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
25
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)
Why not just take the length of LCS(Xi-1, Yj-1) ?
26
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
27
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
3 C 0 c[i - 1, j] ≥ c[i, j-1]
c[i,j-1]
0 b[i, j] = “ ”
m D 0 else
j b[i, j] = “ ”
28
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
Case 1: xi = yj
8. then c[i, j] ← c[i - 1, j - 1] + 1
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)
29
Example
0 if i = 0 or
X = A, B, C, B, D, A j = 0
Y = B, D, C, A, B, A c[i, j] = c[i-1, j-1] + 1 if xi = yj
0 1 2
max(c[i, 3
j-1], 4
c[i-1,5j]) if6 x y
i j
If xi = yj yj B D C A B A
0 xi
b[i, j] = “ ” 0 0 0 0 0 0 0
1 A
0 1
Else if c[i - 0 0 0 1 1
2 B
1, j] ≥ c[i, j-1] 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
30
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
31
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)
Initial call: PRINT-LCS(b, X, length[X], length[Y])
32
LCS
For instance,
Sequence 1: president
Sequence 2: providence
Its LCS is priden.
president
providence
LCS
Another example:
Sequence 1: algorithm
Sequence 2: alignment
One of its LCS is algm.
a l g o r i t h m
a l i g n m e n t
i j 0 1 2 3 4 5 6 7 8 9 10
p r o v i d e n c e
0 0 0 0 0 0 0 0 0 0 0 0
1 p 0 1 1 1 1 1 1 1 1 1 1
2 r 0 1 2 2 2 2 2 2 2 2 2
3 e 0 1 2 2 2 2 2 3 3 3 3
4 s 0 1 2 2 2 2 2 3 3 3 3
5 i 0 1 2 2 2 3 3 3 3 3 3
6 d 0 1 2 2 2 3 4 4 4 4 4
7 e 0 1 2 2 2 3 4 5 5 5 5
8 n 0 1 2 2 2 3 4 5 6 6 6
9 t 0 1 2 2 2 3 4 5 6 6 6
Running time and memory: O(mn) and O(mn).
i j 0 1 2 3 4 5 6 7 8 9 10
p r o v i d e n c e
0 0 0 0 0 0 0 0 0 0 0 0
1 p 0 1 1 1 1 1 1 1 1 1 1
2 r 0 1 2 2 2 2 2 2 2 2 2
3 e 0 1 2 2 2 2 2 3 3 3 3
4 s 0 1 2 2 2 2 2 3 3 3 3
5 i 0 1 2 2 2 3 3 3 3 3 3
6 d 0 1 2 2 2 3 4 4 4 4 4
7 e 0 1 2 2 2 3 4 5 5 5 5
8 n 0 1 2 2 2 3 4 5 6 6 6
9 t 0 1 2 2 2 3 4 5 6 6 6
Output: priden
37