10 DP
10 DP
Dynamic programming
Nội dung
Tìm hiểu về quy hoạch động (dynamic programming)
qua các ví dụ tiêu biểu:
0. Fibonacci Numbers
1. Longest common subsequence
2. Knapsack problem
Sử dụng một phần tài liệu bài giảng CS161 Stanford University
2
Khởi động: Fibonacci Numbers
• Definition:
• F(n) = F(n-1) + F(n-2), with F(1) = F(2) = 1.
• The first several are:
• 1
• 1
• 2
• 3
• 5
• 8
• 13, 21, 34, 55, 89, 144,…
• Question:
• Given n, what is F(n)?
3
Candidate algorithm
• def Fibonacci(n):
• if n == 0, return 0
• if n == 1, return 1
• return Fibonacci(n-1) + Fibonacci(n-2)
Running time?
• T(n) = T(n-1) + T(n-2) + O(1)
• T(n) T(n-1) + T(n-2) for n
• So T(n) grows at least as fast as
the Fibonacci numbers
themselves…
• You showed in HW1 that this is
EXPONENTIALLY QUICKLY!
4
See IPython notebook for lecture 12
What’s going on? That’s a lot of
repeated
Consider Fib(8) computation!
6 7
4 5 5 6
2 3 3 4 3 4 4 5
0 1 1 2 1 2 2 3 1 2 2 3 2 3 3 4
1 2 etc
0 1 1 2
0 1 0 1 1 2 0 1 0 1 0 1 1 2
5
0 1 0 1 0 1 0 1
Maybe this would be better:
8 def fasterFibonacci(n):
• F = [0, 1, None, None, …, None ]
• \\ F has length n + 1
• for i = 2, …, n:
7
• F[i] = F[i-1] + F[i-2]
• return F[n]
1
6
0
This was an example of…
7
What is dynamic programming?
• Là một chiến lược thiết kế thuật toán (an algorithm
design paradigm)
• Các bạn đã học chiến lược chia để trị (divide-and-
conquer).
• Thường dùng để giải các bài toán tối ưu
• Ví dụ, các dạng tìm đường đi ngắn nhất
• Tính số Fibonacci không phải là bài toán tối ưu, nhưng là
một ví dụ đơn giản để thuyết minh DP
8
Elements of dynamic programming
• Optimal substructure.
• Optimal solutions to sub-problems can be used to find the
optimal solution of the original problem.
• Overlapping subproblems.
• The subproblems show up again and again
• Top down
• Bottom up
• For Fibonacci:
• Solve the small problems first
• fill in F[0],F[1]
• Then bigger problems
• fill in F[2]
•…
• Then bigger problems
• fill in F[n-1]
• Then finally solve the real problem.
• fill in F[n]
11
Top down approach
• Think of it like a recursive algorithm.
• To solve the big problem:
• Recurse to solve smaller problems
• Those recurse to solve smaller problems
• etc..
13
Memo-ization visualization
8
6 7
4 5 5 6
2 3 3 4 3 4 4 5
0 1 1 2 1 2 2 3 1 2 2 3 2 3 3 4
1 2 etc
0 1 1 2
0 1 0 1 1 2 0 1 0 1 0 1 1 2
0 1 0 1 0 1 0 1
14
C++ Implementation
int fibo(int f[], int n) {
if (f[n] >=0) return f[n];
return (f[n] = fibo(f, n-1) + f[n-2]);
}
int main() {
int n;
cin >> n;
int a[n+1];
a[0] = 0, a[1] = 1;
for (int i=2; i<=n; i++) a[i] = -1;
cout << fibo(a, n) << endl;
}
15
Nội dung
Tìm hiểu về quy hoạch động (dynamic programming)
qua các ví dụ tiêu biểu:
0. Fibonacci Numbers
1. Longest common subsequence
2. Knapsack problem
16
Longest Common Subsequence
• How similar are these two species?
DNA: DNA:
AGCCCTAAGGGCTACCTAGCTT GACAGCCTACAAGCGTTAGCTTG
17
Longest Common Subsequence
• How similar are these two species?
DNA: DNA:
AGCCCTAAGGGCTACCTAGCTT GACAGCCTACAAGCGTTAGCTTG
• Pretty similar, their DNA has a long common subsequence:
AGCCTAAGCTTAGCTT
18
Longest Common Subsequence
• Subsequence:
• BDFH is a subsequence of ABCDEFGH
• If X and Y are sequences, a common subsequence
is a sequence which is a subsequence of both.
• BDFH is a common subsequence of ABCDEFGH and of
ABDFGHI
• A longest common subsequence…
• …is a common subsequence that is longest.
• The longest common subsequence of ABCDEFGH and
ABDFGHI is ABDFGH.
19
Recipe for applying Dynamic Programming
• Step 1: Identify optimal substructure.
• Step 2: Find a recursive formulation for the length
of the longest common subsequence.
• Step 3: Use dynamic programming to find the
length of the longest common subsequence.
• Step 4: If needed, keep track of some additional
info so that the algorithm from Step 3 can find the
actual LCS.
• Step 5: If needed, code this up like a reasonable
person.
20
Step 1: Optimal substructure
Prefixes:
X A C G G T
Y A C G C T T A
Xi A C G G A
j
Yj A C G C T T A
Yj A C G C T T A
Case 0
Case 1 Case 2
A C G G A A C G G T
Xi Xi
Yj A C G C T T A Yj A C G C T T
24
A
LCS DP
• LCS(X, Y):
• C[i,0] = C[0,j] = 0 for all i = 0,…,m, j=0,…n.
• For i = 1,…,m and j = 1,…,n:
• If X[i] = Y[j]:
• C[i,j] = C[i-1,j-1] + 1
• Else:
• C[i,j] = max{ C[i,j-1], C[i-1,j] }
• Return C[m,n]
25
X A C G G A
Example
Y A C T G
Y
A C T G
0 0 0 0 0
A 0
C 0
X G 0
G 0
A 0
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = 𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and26 𝑖, 𝑗 > 0
X A C G G A
Example
Y A C T G
Y
A C T G
0 0 0 0 0
A 0 1 1 1 1 So the LCM of X
C 0 1 2 2 2 and Y has length 3.
X G 0 1 2 2 3
G 0 1 2 2 3
A 0 1 2 2 3
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = 𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and27 𝑖, 𝑗 > 0
Recipe for applying Dynamic Programming
• Step 1: Identify optimal substructure.
• Step 2: Find a recursive formulation for the length
of the longest common subsequence.
• Step 3: Use dynamic programming to find the
length of the longest common subsequence.
• Step 4: If needed, keep track of some additional
info so that the algorithm from Step 3 can find the
actual LCS.
• Step 5: If needed, code this up like a reasonable
person.
28
X A C G G A
Example
Y A C T G
Y
A C T G
• Once we’ve filled this in,
we can work backwards.
0 0 0 0 0
A 0 1 1 1 1
C 0 1 2 2 2
X G 0 1 2 2 3
G 0 1 2 2 3
A 0 1 2 2 3
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = 𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and29 𝑖, 𝑗 > 0
X A C G G A
Example
Y A C T G
Y
A C T G
• Once we’ve filled this in,
we can work backwards.
0 0 0 0 0
A 0 1 1 1 1
C 0 1 2 2 2
X G 0 1 2 2 3
Example
Y A C T G
Y
A C T G
• Once we’ve filled this in,
we can work backwards.
0 0 0 0 0 • A diagonal jump means
that we found an element
A 0 1 1 1 1
of the LCS!
C 0 1 2 2 2
A 0 1 2 2 3
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = 𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and31 𝑖, 𝑗 > 0
X A C G G A
Example
Y A C T G
Y
A C T G
• Once we’ve filled this in,
we can work backwards.
0 0 0 0 0 • A diagonal jump means
that we found an element
A 0 1 1 1 1
of the LCS!
C 0 1 2 2 2 That 2 may as well
have come from
X G 0 1 2 2 3
this other 2. G
G 0 1 2 2 3
A 0 1 2 2 3
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = 𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and32 𝑖, 𝑗 > 0
X A C G G A
Example
Y A C T G
Y
A C T G
• Once we’ve filled this in,
we can work backwards.
0 0 0 0 0 • A diagonal jump means
that we found an element
A 0 1 1 1 1
of the LCS!
C 0 1 2 2 2
X G 0 1 2 2 3 G
G 0 1 2 2 3
A 0 1 2 2 3
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = 𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and33 𝑖, 𝑗 > 0
X A C G G A
Example
Y A C T G
Y
A C T G
• Once we’ve filled this in,
we can work backwards.
0 0 0 0 0 • A diagonal jump means
that we found an element
A 0 1 1 1 1
of the LCS!
C 0 1 2 2 2
X G 0 1 2 2 3 C G
G 0 1 2 2 3
A 0 1 2 2 3
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = 𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and34 𝑖, 𝑗 > 0
X A C G G A
Example
Y A C T G
Y
A C T G
• Once we’ve filled this in,
we can work backwards.
0 0 0 0 0 • A diagonal jump means
that we found an element
A 0 1 1 1 1
of the LCS!
C 0 1 2 2 2
X G 0 1 2 2 3 A C G
G 0 1 2 2 3
This is the LCS!
A 0 1 2 2 3
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = 𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and35 𝑖, 𝑗 > 0
Nội dung
Tìm hiểu về quy hoạch động (dynamic programming)
qua các ví dụ tiêu biểu:
0. Fibonacci Numbers
1. Longest common subsequence
2. Knapsack problem
36
Example 2: Knapsack Problem
• We have n items with weights and values:
Item:
Weight: 6 2 4 3 11
Value:
20 8 14 13 35
37
Some notation
Item:
Weight: w1 w2 w3 … wn
Value: v1 v2 v3 vn
Capacity: W
38
Item:
Weight: 6 2 4 3 11
Capacity: 10 Value: 20 8 14 13 35
• Unbounded Knapsack:
• Suppose I have infinite copies of all of the items.
• What’s the most valuable way to fill the knapsack?
Total weight: 10
Total value: 42
• 0/1 Knapsack:
• Suppose I have only one copy of each item.
• What’s the most valuable way to fill the knapsack?
Total weight: 9
Total value: 35
39
Recipe for applying Dynamic Programming
• Step 1: Identify optimal substructure.
• Step 2: Find a recursive formulation for the value of
the optimal solution.
• Step 3: Use dynamic programming to find the value
of the optimal solution.
• Step 4: If needed, keep track of some additional
info so that the algorithm from Step 3 can find the
actual solution.
• Step 5: If needed, code this up like a reasonable
person.
40
Optimal substructure: try 2
• Sub-problems:
• 0/1 Knapsack with fewer items.
Then yet
more
items
41
Our sub-problems:
• Indexed by x and j
Capacity x
Value V
First j items Use only the first j items
45
Two cases item j
Capacity x
Value V
First j items Use only the first j items
Capacity x
Value V 46
First j-1 items Use only the first j-1 items.
Two cases item j
Weight wj
Value vj Capacity x
Value V
First j items Use only the first j items
47
Two cases item j
Weight wj
Value vj Capacity x
Value V
First j items Use only the first j items
• Then this is an optimal solution for j-1 items and a
smaller knapsack:
Capacity x – wj
Value V – vj
First j-1 items Use only the first j-148items.
Recursive relationship
• Let K[x,j] be the optimal value for:
• capacity x,
• with j items.
49
Bottom-up DP algorithm
• Zero-One-Knapsack(W, n, w, v):
• K[x,0] = 0 for all x = 0,…,W
• K[0,i] = 0 for all i = 0,…,n
• for x = 1,…,W:
• for j = 1,…,n: Case 1
• K[x,j] = K[x, j-1]
• if wj x: Case 2
• K[x,j] = max{ K[x,j], K[x – wj, j-1] + vj }
• return K[W,n]
0
j=1
0
j=2
0
j=3
Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity:
51 3
• Zero-One-Knapsack(W, n, w, v):
• K[x,0] = 0 for all x = 0,…,W
• K[0,i] = 0 for all i = 0,…,n
0 0
j=1
0
j=2
0
j=3
Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity:
52 3
• Zero-One-Knapsack(W, n, w, v):
• K[x,0] = 0 for all x = 0,…,W
• K[0,i] = 0 for all i = 0,…,n
0 1
j=1
0
j=2
0
j=3
Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity:
53 3
• Zero-One-Knapsack(W, n, w, v):
• K[x,0] = 0 for all x = 0,…,W
• K[0,i] = 0 for all i = 0,…,n
0 1 1
j=1
0 1 4
j=2
0 1
j=3
Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity:
54 3
• Zero-One-Knapsack(W, n, w, v):
• K[x,0] = 0 for all x = 0,…,W
• K[0,i] = 0 for all i = 0,…,n
0 1 1
j=1
0 1 4
j=2
0 1 4
j=3
Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity:
55 3
• Zero-One-Knapsack(W, n, w, v):
• K[x,0] = 0 for all x = 0,…,W
• K[0,i] = 0 for all i = 0,…,n
0 1 1 1
j=1
0 1 4 5
j=2
So the optimal solution is to
0 1 4 6 put one watermelon in your
j=3 knapsack!
Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity:
56 3
What have we learned?
57
Why “dynamic programming” ?
• Programming refers to finding the optimal “program.”
• as in, a shortest route is a plan aka a program.
• Dynamic refers to the fact that it’s multi-stage.
• But also it’s just a fancy-sounding name.
59