Week8 9 Chap5 Dynamic Programming
Week8 9 Chap5 Dynamic Programming
APPLIED ALGORITHMS
DYNAMIC PROGRAMMING
3
CONTENTS
4
History of dynamic programming
• R.E.Bellman (1920-1984)
5
What is dynamic programming ?
1 2 3 4 5 6 7 8
6
What is dynamic programming ?
• Dynamic programming
• Divide the original problem into overlapping subproblems
• Recurrence relations
• Solution to a subproblem is specified based on solutions to smaller subproblems
• Top-down approach (by recursion):
• Solve subproblems are solved recursively
• Base-case: solutions to the smallest subproblems are computed trivially (no recursion)
• Bottom-up:
• Smallest subproblems are solved trivially
• Specify the solution to each subproblem based on the solutions to smaller subproblems
(using recurrence relations)
• Do not find the solution to the same problem more than one time (memorization)
7
Top-Down implementation with memorized recursion
if (Memory.find(P) != Memory.end())
return Memory [P];
8
Fibonacci numbers
• The first two numbers of Fibonacci sequence are 1 and 1. All other numbers in the sequence are
calculated as the sum of the two numbers immediately preceding them in the sequence.
• Requirement: Calculate the nth Fibonacci number
• Try to solve the problem by using dynamic programming
1. Find recursive formular:
9
Fibonacci numbers
if (mem.find(n) != mem.end())
return mem[n];
return res;
}
10
Fibonacci numbers
return res;
}
• What is the complexity ?
11
Fibonacci numbers: Complexity
12
CONTENTS
13
Money change
• Given a set of coins with denominations D1, D2, ..., Dn and an amount of money X.
Find the minimum number of coins to exchange for X.
• Like the knapsack problem?
• Is there a greedy algorithm to solve this problem?
• The knapsack problem learned in Discrete Mathematics is solved using the branch
and bound algorithm. The greedy algorithm is not certain of providing the optimal
solution, and in many cases cannot even provide the solution...
• Try using the Dynamic Programming method!
• Finally, make comments on different approaches to solving this problem
14
Money change: dynamic programming formular
• Recurrence relation:
15
Money change: Implementation
17
Money change: Tracing using recursion
18
CONTENTS
19
Longest increasing subsequence (LIS)
• Given a sequence of n integers A[1], A[2], ..., A[n]. Find the length of the longest
increasing subsequence.
• Definition: If delete 0 or some elements of the sequence A, a subsequence of A will
be obtained.
Example: A = [2, 0, 6, 1, 2, 9]
• [2, 6, 9] is a subsequence of A
• [2, 2] is a subsequence of A
• [2, 0, 6, 1, 2, 9] is a subsequence of A
• [] is a subsequence of A
• [9, 0] is not a subsequence of A
• [7] is not a subsequence of A
20
Longest increasing subsequence (LIS)
21
Longest increasing subsequence (LIS)
• Let LIS(i) be the length of the longest increasing subsequence of the array A[1],
A[2], ..., A[i] that ends at the ith element.
• Base case: LIS(1) = 1
• Recurrence relation:
22
Longest increasing subsequence (LIS)
int LIS(i) {
if (mem[i] != -1) return mem[i];
int res = 1;
for (int j = 1; j < i; j++){
if (a[j] < a[i])
res = max(res, 1 + LIS(j));
}
mem[i] = res;
return res;
}
23
Longest increasing subsequence (LIS)
• The length of the longest increasing subsequence is the largest value among the
LIS(i) values.
24
The longest increasing subsequence: Complexity
25
Longest increasing subsequence (LIS): improvement using binary search
26
Longest increasing subsequence (LIS): improvement using binary search
• Example A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1]
• i = 1: A[1] = 4 → L[1] = [4]
• i = 2: A[2] = 2 → L[1] = [2]
• i = 3: A[3] = 6 → L[1] = [2], L[2] = [2, 6]
• i = 4: A[4] = 3 → L[1] = [2], L[2] = [2, 3] (replace [2,6] by [2,3] in which 3 is smaller than 6)
• i = 5: A[5] = 8 → L[1] = [2], L[2] = [2, 3], L[3] = [2, 3, 8] (create new list L[3] by adding 8 at the end
of L[2]
• i = 6: A[6] = 4 → L[1] = [2], L[2] = [2, 3], L[3] = [2, 3, 4] (replace [2, 3, 8] by [2, 3, 4] in which 4 is
smaller than 8)
• i = 7: A[7] = 5 → L[1] = [2], L[2] = [2, 3], L[3] = [2, 3, 4], L[4] = [2, 3, 4, 5] (create new list L[4])
• i = 8: A[8] = 9 → L[1] = [2], L[2] = [2, 3], L[3] = [2, 3, 4], L[4] = [2, 3, 4, 5], L[5] = [2, 3, 4, 5, 9]
• i = 9: A[9] = 6 → L[1] = [2], L[2] = [2, 3], L[3] = [2, 3, 4], L[4] = [2, 3, 4, 5], L[5] = [2, 3, 4, 5, 6]
• i = 10: A[10] = 1 → L[1] = [1], L[2] = [2, 3], L[3] = [2, 3, 4], L[4] = [2, 3, 4, 5], L[5] = [2, 3, 4, 5, 6]
27
Longest increasing subsequence (LIS): improvement using binary search
#include <bits/stdc++.h> int main(){
using namespace std; input();
vector<int> A; for(int i = 0; i< n; i++){
int n; vector<int>::iterator p =
vector<int> x; lower_bound(x.begin(), x.end(), A[i]);
void input(){ int lb = p - x.begin();
scanf("%d",&n); if(lb == x.size()){ x.push_back(A[i]); }
for(int i = 0; i< n; i++){ else{ x[lb] = A[i]; }
int v; scanf("%d",&v); A.push_back(v); }
} int res = x.size();
} cout << res;
return 0;
}
28
Longest increasing subsequence (LIS): improvement using segment trees
• Sort the sequence in non-decreasing order of values, maintain indices of the elements in the original
sequence:
• index[i] is the index of element A[i] in the sorted sequence
• If two elements A[i] = A[j] with i < j, then A[i] is located after A[j] in the sorted sequence: index[i] >
index[j]
29
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1]
1 2 3 4 5 6 7 8 9 10
4 2 6 3 8 4 5 9 6 1
Sort
1 2 3 4 5 6 7 8 9 10
A 4 2 6 3 8 4 5 9 6 1
1 2 3 4 4 5 6 6 8 9 index 5 2 8 3 9 4 6 10 7 1
• Scan the original sequence from left to right, for each index i:
• compute the length LIS[i] of the longest increasing subsequence of A[1], A[2], . . ., A[i]:
• LIS[i] = result[index[i]] = max(result[1],. . ., result[index[i] – 1]) + 1
• Use a segment tree to query max(result[1],. . ., result[index[i] – 1])
30
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 1: index[1] = 5, LIS[1] = result[5] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..4] + 1) = 1 index 5 2 8 3 9 4 6 10 7 1
1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 0 0 0 1 0 0 0 0 0
31
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 2: index[2] = 2, LIS[2] = result[2] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..1] + 1) = 1 index 5 2 8 3 9 4 6 10 7 1
1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 0 0 1 0 0 0 0 0
32
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 3: index[3] = 8, LIS[3] = result[8] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..7] + 1) = 2 index 5 2 8 3 9 4 6 10 7 1
1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 0 0 1 0 0 2 0 0
33
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 4: index[4] = 3, LIS[4] = result[3] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..2] + 1) = 2 index 5 2 8 3 9 4 6 10 7 1
1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 0 1 0 0 2 0 0
34
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 5: index[5] = 9, LIS[5] = result[9] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..8] + 1) = 3 index 5 2 8 3 9 4 6 10 7 1
1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 0 1 0 0 2 3 0
35
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 6: index[6] = 4, LIS[6] = result[4] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..3] + 1) = 3 index 5 2 8 3 9 4 6 10 7 1
1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 3 1 0 0 2 3 0
36
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 7: index[7] = 6, LIS[7] = result[6] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..5] + 1) = 4 index 5 2 8 3 9 4 6 10 7 1
1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 3 1 4 0 2 3 0
37
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 8: index[8] = 10, LIS[8] = result[10] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..9] + 1) = 5 index 5 2 8 3 9 4 6 10 7 1
1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 3 1 4 0 2 3 5
38
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 9: index[9] = 7, LIS[9] = result[7] = A 4 2 6 3 8 4 5 9 6 1
max(result[1..6] + 1) = 5 index 5 2 8 3 9 4 6 10 7 1
1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 0 1 2 3 1 4 5 2 3 5
39
Longest increasing subsequence (LIS): improvement using segment trees
• Example: A = [4, 2, 6, 3, 8, 4, 5, 9, 6, 1] 1 2 3 4 5 6 7 8 9 10
• Step i = 10: index[10] = 1, LIS[10] = result[1] = A 4 2 6 3 8 4 5 9 6 1
max(result[0..0] + 1) = 1 index 5 2 8 3 9 4 6 10 7 1
1 2 3 4 5 6 7 8 9 10
SA 1 2 3 4 4 5 6 6 8 9
result 1 1 2 3 1 4 5 2 3 5
40
Longest increasing subsequence (LIS): Tracing using recursion
void Trace(int i) {
for (int j = 1; j < i; j++){
if (a[j] < a[i] && mem[i] == 1 + mem[j]){
Trace(j);
break;
}
}
cout << a[i] << ' ';
}
• Call Trace(pos);
• The complexity of Trace function? O(n2)
• Can be improved: O(n)
41
Longest increasing subsequence (LIS): Tracing using recursion (improved)
void Trace(int i) {
for (int j = i - 1; j >= 1; j--){
if (a[j] < a[i] && mem[i] == 1 + mem[j]){
Trace(j);
break;
}
}
cout << a[i] << ' ';
}
• Call Trace(pos);
• The complexity of Trace function? O(n)
42
Longest increasing subsequence (LIS): Tracing using loop
stack<int> stk;
int i = pos;
while (!stk.empty()) {
cout << stk.top() << ' ';
stk.pop();
}
}
43
CONTENTS
44
Longest common subsequence (Dãy con chung dài nhất)
• Given two strings (or two integer arrays) of n and m elements X[1], X[2], ..., X[n] và
Y[1], Y[2],..., Y[m]. Find the length of the longest common subsequence of the two
strings.
• Example: X = "abcb", Y = "bdcab"
• The longest common subsequence of X and Y is là "bcb" which has the length 3.
45
Longest common subsequence: Dynamic programming formular
• Let LCS(i, j) be the length of the longest common subsequence of the sequences
X[1], X[2], ..., X[i] and Y[1], Y[2], ..., Y[j].
• Basic step:
L(0, j) = L(i, 0) = 0
• Inductive step:
46
Longest common subsequence: Implement
48
Longest common subsequence: Complexity
49
Longest common subsequence: Tracing by using recursion
void Trace(int i, int j) {
if (i == 0 || j == 0) return;
if (X[i-1] == Y[j-1] && mem[i][j] == 1 + mem[i-1][j-1]) {
Trace(i - 1, j - 1);
cout << X[i-1];
return;
}
if (mem[i][j] == mem[i-1][j]) {
Trace(i - 1, j);
return;
}
if (mem[i][j] == mem[i][j-1]) {
Trace(i, j - 1);
return;
}
}
50
Longest common subsequence: Tracing by using recursion
51
Longest common subsequence: Tracing by using loop
void IterTrace() {
int i = X.size(), j = Y.size();
stack<int> stk;
int ans = LCS(i, j);
for (int k = 0; k < ans; k++) {
if (X[i - 1] == Y[j - 1] && mem[i][j] == 1 + mem[i-1][j-1]) {
stk.push(X[i - 1]); i--; j--; continue;
}
if (mem[i][j] == mem[i-1][j]) {
i--; continue;
}
if(mem[i][j] == mem[i][j-1]) {
j--; continue;
}
}
while (!stk.empty()){
cout << stk.top() << ' ';
stk.pop();
}
}
52
CONTENTS
53
Bitmask
54
Traveling salesman problem
• “The history and evolution of solutions to the Traveling Salesman Problem can provide
us with some valuable concepts for business analytics and algorithm development”
• ”Just as the traveling salesman makes his journey, new analytical requirements arise
that require a journey into the development of solutions for them. As the data science
and business analytics landscape evolves with new solutions, we can learn from the
history of these journeys and apply the same concepts to our ongoing development”
55
Traveling salesman problem
• Given a graph of n vertices {0, 1, ..., n – 1} and the weight value Ci,j on each pair of
vertices i, j. Find a cycle that goes through all the vertices of the graph, each vertex
exactly once, so that the sum of the weights on that cycle is minimum.
56
Traveling salesman problem: Dynamic programming
• Without loss of generality, assume the cycle begins and ends at vertex 0.
• Let TSP(i, S) be the shortest route starting from vertex i, visiting all vertices in S and returning to
vertex 0.
• Base case: TSP(i, {}) = Ci,0
• Recurrence relation:
• TSP(i, S) = minjS{ Ci,j + TSP(j, S \ {j})}
• Solution to the original problem is TSP(0, {1, 2, . . ., n-1})
j
i . . . 0
S
57
Traveling salesman problem: Dynamic programming
• Bitmasking:
• A subset of {0, 1, 2, . . ., n-1} is represented by a sequence of bits bit bn-1bn-2…b0
• bi = 1 means that i belongs to the subset, and bi = 0 means that i does not belong to the subset
• The sequence bn-1bn-2…b0 is represented by a non-negative integer N
• Perform bit manipulation on N to reflect the corresponding set operations: insertion,
removal, existence checking
unsigned int removeItem(unsigned int S, int i){ bool contains(unsigned int S, int i){
return S ^ (1 << i); if(((S >> i) & 1) > 0)
} return true;
unsigned int addItem(unsigned int S, int i){ else return false;
return S | (1 << i); }
}
58
Traveling salesman problem: Dynamic programming
59
THANK YOU !
60