Lecture 6 1
Lecture 6 1
Lecture 6 1
Analysis of Algorithms
FALL 2020-2021
Lecture 6
Analysis of Algorithms
Part II: Algorithm Design Techniques
• Programming paradigms
• Dynamic programming:
• matrix chain multiplication problem
• longest common subsequence problem
• rod cuting problem
• Greedy algorithms:
• activity selection problem
• fractional knapsack problem
Dynamic Programming
Dynamic Programming is a general algorithm design technique
for solving problems defined by or formulated as recurrences with overlapping
subinstances
• Main idea:
- set up a recurrence relating a solution to a larger instance to solutions of some
smaller instances
- solve smaller instances once
- record solutions in a table
- extract solution to the initial instance from that table
Example: Fibonacci numbers
• Recall definition of Fibonacci numbers:
F(n)
F(n-1) + F(n-2)
...
Example: Fibonacci numbers (cont.)
Computing the nth Fibonacci number using bottom-up iteration and
recording results:
F(0) = 0
F(1) = 1
F(2) = 1+0 = 1
…
F(n-2) =
F(n-1) =
F(n) = F(n-1) + F(n-2)
MATRIX-MULTIPLY(Ap×q , Bq×r)
1. for i ← 1 to p
2. for j ← 1 to r
3. C[i, j] ← 0
4. for k ← 1 to q
5. C[i, j] ← C[i, j] + A[i, k] · B[k, j]
6. return C
Total:
75,000
Matrix-chain Multiplication …contd
0 if i=j
m[i, j ] =
min {m[i, k] + m[k+1, j ] + pi-1pk pj } if i<j
i ≤ k< j
Dynamic Programming Approach …contd
• To keep track of how to construct an optimal
solution, we use a table s
• s[i, j ] = value of k at which Ai Ai+1 … Aj is split for
optimal parenthesization
• Algorithm: next slide
• First computes costs for chains of length l=1
• Then for chains of length l=2,3, … and so on
• Computes the optimal cost bottom-up
Algorithm to Compute Optimal Cost
Input: Array p[0…n] containing matrix dimensions and n
Result: Minimum-cost table m and split table s
MATRIX-CHAIN-ORDER(p[ ], n)
for i ← 1 to n Takes O(n3) time
m[i, i] ← 0
Requires O(n2) space
for l ← 2 to n
for i ← 1 to n-l+1
j ← i+l-1
m[i, j] ←
for k ← i to j-1
q ← m[i, k] + m[k+1, j] + p[i-1] p[k] p[j]
if q < m[i, j]
m[i, j] ← q
s[i, j] ← k
return m and s
Constructing Optimal Solution
• Our algorithm computes the minimum-cost table
m and the split table s
• The optimal solution can be constructed from the
split table s
• Each entry s[i, j ]=k shows where to split the product Ai
Ai+1 … Aj for the minimum cost
Example
Matrix A1 A2 A3 A4 A5 A6
Dimensions 10x20 20x5 5x15 15x50 50x10 10x15
The problem therefore can be phrased as one
of filling in the following table representing the
values m.
i\j 1 2 3 4 5 6
1 0
2 0
3
0
4
5 0
6 0
0
21
Example (Contd.)
i\j 1 2 3 4 5 6
1 0 1000
2 0 1500
3
0 3750
4
5 0 7500
6 0 7500
0
22
Example (Contd.)
Chains of length 3 require some minimization –
but only one each.
m[1,3]=min{(m[1,1]+m[2,3]+p 0p1p3),(m[1,2]+m[3,3]+p0p2p3)}
= min{(0+1500+10x20x15),
(1000+0+10x5x15)}
= min { 4500,1p1750
m[2,4]=min{(m[2,2]+m[3,4]+p } = 1750
2p4),(m[2,3]+m[4,4]+p 1p3p4)}
= min{(0+3750+20x5x50),
(1500+0+20x15x50)}
= min { 8750,2p16500
m[3,5]=min{(m[3,3]+m[4,5]+p } = 8750
3p5),(m[3,4]+m[5,5]+p 2p4p5)}
= min{(0+7500+5x15x10),
(3750+0+5x50x10)}
= min { 8250,3p6250
m[4,6]=min{(m[4,4]+m[5,6]+p } = 6250
4p6),(m[4,5]+m[6,6]+p 3p5p6)}
= min{(0+7500+15x50x15),
(7500+0+15x10x15)}
= min { 18750, 9750 } = 9750
i\j 1 2 3 4 5 6
1 0 1000 1750
2 0 1500 8750
3
0 3750 6250
4
5 0 7500 9750
6 0 7500
0
23
Example (Contd.)
m[1,4]=min{(m[1,1]+m[2,4]+p 0p1p4),(m[1,2]+m[3,4]+p0p2p4),
(m[1,3]+m[4,4]+p0p3p4)}
= min{(0+8750+10x20x50),
(1000+3750+10x5x50),
(1750+0+10x15x50)}
m[2,5]=min{(m[2,2]+m[3,5]+p 1p27250,
= min { 18750, p5),(m[2,3]+m[4,5]+p
9250 } = 72501p3p5),
(m[2,4]+m[5,5]+p1p4p5)}
= min{(0+6250+20x5x10),
(1500+7500+20x15x10),
(8750+0+20x50x10)}
m[3,6]=min{(m[3,3]+m[4,6]+p
= min { 7250,2p12000,
3p6),(m[3,4]+m[5,6]+p
18750 } = 7250 2p4p6),
(m[3,5]+m[6,6]+p2p5p6)}
= min{(0+9750+5x15x15),
(3750+7500+5x50x15),
(6250+0+5x10x15)}
i\j 1 =2 3
min { 10875, 4
15000, 5 } = 7000
7000 6
1 0 1000 1750 7250
2 0 1500 8750 7250
3
0 3750 6250 7000
4
5 0 7500 9750
6 0 7500
0
24
Example (Contd.)
m[1,5]=min{(m[1,1]+m[2,5]+p 0p1p5),(m[1,2]+m[3,5]+p0p2p5),
(m[1,3]+m[4,5]+p0p3p5),
(m[1,4]+m[5,5]+p0p4p5)}
= min{(0+7250+10x20x10),
(1000+6250+10x5x10),
(1750+7500+10x15x10),
m[2,6]=min{(m[2,2]+m[3,6]+p 1p2p6),(m[2,3]+m[4,6]+p 1p3p6),
(7250+0+10x50x10)} (m[2,4]+m[5,6]+p1p4p6),
(m[2,5]+m[6,6]+p= pmin
p )}{ 9250, 7750, 10750, 12250 } = 7750
1 5 6
= min{(0+7000+20x5x15),
(1500+9750+20x15x15),
(8750+7500+20x50x15),
m[1,6]=min{(m[1,1]+m[2,6]+p 0p1p6),(m[1,2]+m[3,6]+p 0p2p6),
(7250+0+20x10x15)}
(m[1,3]+m[4,6]+p p p ),
= min { 8500, 15750, 31,250, 102500 3 } 6=
(m[1,4]+m[5,6]+p
8500 p p
0 4 6),
(m[1,5]+m[6,6]+p0p5p6)}
i\j 1 = 2min{(11500,
3 8750,
4 13750,
5 22250,
6 9250 }
= 8750
1 0 1000 1750 7250 7750 8750
2 0 1500 8750 7250 8500
3
0 3750 6250 7000
4
5 0 7500 9750
6 0 7500
0
25
Dynamic Programming Approach (Contd.)
The algorithm takes O(n3) time and requires O(n2)
space.
Step 4: Constructing an optimal solution
Our algorithm computes the minimum-cost
table m and the split table s.
The optimal solution can be constructed from
the split table s.
Each entry s[i, j ]=k shows where to split the
product Ai Ai+1 … Aj for the minimum cost.
The following recursive procedure prints an
optimal parenthesization.
Algorithm PrintOptimalPerens(s, i, j)
{ if (i=j) then
Print “A”i;
else
{ Print “(“;
PrintOptimalPerens(s, i, s[i,j]);
PrintOptimalPerens(s, s[i,j]+1,
j);
Print “)”;
26 }
}
Example (Contd.)
So far we have decided that the best way to
parenthesize the expression results in 8750
multiplication.
But we have not addressed how we should
actually DO the multiplication to achieve the
value.
However, look at the last computation we did –
the minimum value came from computing
A = (A1A2)
(A3A4A5A6)
then we set
s[i, j] = k.
A = ((A1A2)
(((A3A4)A5)A6)).
c[i 1, j 1] 1 if x[i ] y[ j ],
c[i, j ]
max(c[i, j 1], c[i 1, j ]) otherwise
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)
LCS(X, Y) = BCB
X=AB C B
Y= BDCAB
LCS Example (0) ABCB
j 0 1 2 3 4 5
BDCAB
i Yj B D C A B
0 Xi
1 A
2 B
3 C
4 B
X = ABCB; m = |X| = 4
Y = BDCAB; n = |Y| = 5
Allocate array c[4,5]
LCS Example (1) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0
2 B 0
3 C 0
4 B 0
for i = 1 to m c[i,0] = 0
for j = 1 to n c[0,j] = 0
LCS Example (2) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0
2 B 0
3 C 0
4 B 0
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (3) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0
2 B 0
3 C 0
4 B 0
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (4) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1
2 B 0
3 C 0
4 B 0
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (5) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0
3 C 0
4 B 0
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (6) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1
3 C 0
4 B 0
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (7) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1 1 1 1
3 C 0
4 B 0
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (8) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1 1 1 1 2
3 C 0
4 B 0
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (10) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1 1 1 1 2
3 C 0 1 1
4 B 0
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (11) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1 1 1 1 2
3 C 0 1 1 2
4 B 0
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (12) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1 1 1 1 2
3 C 0 1 1 2 2 2
4 B 0
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (13) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1 1 1 1 2
3 C 0 1 1 2 2 2
4 B 0 1
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (14) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1 1 1 1 2
3 C 0 1 1 2 2 2
4 B 0 1 1 2 2
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Example (15) ABCB
j 0 1 2 3 4 5
BDCA
i Yj B D C A BB
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1 1 1 1 2
3 C 0 1 1 2 2 2
4 B 0 1 1 2 2 3
if ( Xi == Yj )
c[i,j] = c[i-1,j-1] + 1
else c[i,j] = max( c[i-1,j], c[i,j-1] )
LCS Algorithm Running Time
O(m*n)
since each c[i,j] is calculated in
constant time, and there are m*n
elements in the array
How to find actual LCS
• So far, we have just found the length of LCS, but
not LCS itself.
• We want to modify this algorithm to make it output
Longest Common Subsequence of X and Y
Each c[i,j] depends on c[i-1,j] and c[i,j-1]
or c[i-1, j-1]
For each c[i,j] we can say how it was acquired:
LCS_print(x, m, n, c) {
if (c[m][n] == c[m-1][n]) // go up?
LCS_print(x, m-1, n, c);
else if (c[m][n] == c[m][n-1] // go left?
LCS_print(x, m, n-1, c);
else { // it was a match!
LCS_print(x, m-1, n-1, c);
print(x[m]); // print after recursive call
}
}
Finding LCS
j 0 1 2 3 4 5
i Yj B D C A B
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1 1 1 1 2
3 C 0 1 1 2 2 2
4 B 0 1 1 2 2 3
Finding LCS (2)
j 0 1 2 3 4 5
i Yj B D C A B
0 Xi 0 0 0 0 0 0
1 A 0 0 0 0 1 1
2 B 0 1 1 1 1 2
3 C 0 1 1 2 2 2
4 B 0 1 1 2 2 3
LCS (reversed order): B C B
LCS (straight order): B C B
(this string turned out to be a palindrome)
Knapsack 0-1 Problem
The goal is to maximize
the value of a knapsack
that can hold at most W
units (i.e. lbs or kg) worth
of goods from a list of
items I0, I1, … In-1.
The best set of items from {I0, I1, I2} is {I0, I1, I2}
BUT the best set of items from {I0, I1, I2, I3} is {I0, I2, I3}.
◦ In this example, note that this optimal solution, {I 0, I2, I3}, does NOT build upon
the previous optimal solution, {I0, I1, I2}.
(Instead it build's upon the solution, {I0, I2}, which is really the optimal subset of
Knapsack 0-1 problem
So now we must re-work the way we build upon previous sub-problems…
◦ Let B[k, w] represent the maximum total value of a subset S k with weight w.
◦ Our goal is to find B[n, W], where n is the total number of items and W is the
maximal weight the knapsack can carry.
In English, this means that the best subset of S k that has total weight w is:
1) The best subset of Sk-1 that has total weight w, or
2) The best subset of Sk-1 that has total weight w-wk plus the item k
Knapsack 0-1 Problem –Recursive Formula
Second case: wk ≤ w
◦ Then the item k can be in the solution, and we choose the case
with greater value.
Knapsack 0-1 Algorithm
for w = 0 to W { // Initialize 1st row to 0’s
B[0,w] = 0
}
for i = 1 to n { // Initialize 1st column to 0’s
B[i,0] = 0
}
for i = 1 to n {
for w = 0 to W {
if wi <= w { //item i can be in the solution
if vi + B[i-1,w-wi] > B[i-1,w]
B[i,w] = vi + B[i-1,w- wi]
else
B[i,w] = B[i-1,w]
}
else B[i,w] = B[i-1,w] // wi > w
}
}
Knapsack 0-1 Problem
Let’s run our algorithm on the following data:
◦ n = 4 (# of elements)
◦ W = 5 (max weight)
◦ Elements (weight, value):
(2,3), (3,4), (4,5), (5,6)
Knapsack 0-1 Example
i/w 0 1 2 3 4 5
0 0 0 0 0 0 0
1 0
2 0
3 0
4 0
for i = 1 to n
B[i,0] = 0
Items:
else
B[i,w] = B[i-1,w]
B[i,w] = B[i-1,w]
else B[i,w] = B[i-1,w] // wi > w
Items:
We’re DONE!!
The max possible value that can be carried in this knapsack is $7
Knapsack 0-1 Algorithm
This algorithm only finds the max possible value that
can be carried in the knapsack
◦ The value in B[n,W]
i=n,k=W
while i, k > 0
if B[i, k] ≠ B[i-1, k] then
mark the ith item as in the knapsack
i = i-1, k = k-wi
else
i = i-1
Items: Knapsack:
Knapsack 0-1 Algorithm 1: (2,3)
Finding the Items 2: (3,4)
3: (4,5)
4: (5,6)
i/w 0 1 2 3 4 5
0 0 0 0 0 0 0 i=3
1 0 0 3 3 3 3 k=5
2 0 0 3 4 4 7 vi = 5
3 0 0 3 4 5 7 wi = 4
4 0 0 3 4 5 7 B[i,k] = 7
B[i-1,k] = 7
i=n,k=W
while i, k > 0
if B[i, k] ≠ B[i-1, k] then
mark the ith item as in the knapsack
i = i-1, k = k-wi
else
i = i-1
Items: Knapsack:
Knapsack 0-1 Algorithm 1: (2,3) Item 2
Finding the Items 2: (3,4)
3: (4,5)
4: (5,6)
i/w 0 1 2 3 4 5
0 0 0 0 0 0 0 i=2
1 0 0 3 3 3 3 k=5
2 0 0 3 4 4 7 vi = 4
3 0 0 3 4 5 7 wi = 3
4 0 0 3 4 5 7 B[i,k] = 7
B[i-1,k] =
3
i=n,k=W k – wi = 2
while i, k > 0
if B[i, k] ≠ B[i-1, k] then
mark the ith item as in the knapsack
i = i-1, k = k-wi
else
i = i-1
Items: Knapsack:
Knapsack 0-1 Algorithm 1: (2,3) Item 2
Finding the Items 2: (3,4) Item 1
3: (4,5)
4: (5,6)
i/w 0 1 2 3 4 5
0 0 0 0 0 0 0 i=1
1 0 0 3 3 3 3 k=2
2 0 0 3 4 4 7 vi = 3
3 0 0 3 4 5 7 wi = 2
4 0 0 3 4 5 7 B[i,k] = 3
B[i-1,k] =
0
i=n,k=W k – wi = 0
while i, k > 0
if B[i, k] ≠ B[i-1, k] then
mark the ith item as in the knapsack
i = i-1, k = k-wi
else
i = i-1
Items: Knapsack:
Knapsack 0-1 Algorithm 1: (2,3) Item 2
Finding the Items 2: (3,4) Item 1
3: (4,5)
4: (5,6)
i/w 0 1 2 3 4 5
0 0 0 0 0 0 0 i=1
1 0 0 3 3 3 3 k=2
2 0 0 3 4 4 7 vi = 3
3 0 0 3 4 5 7 wi = 2
4 0 0 3 4 5 7 B[i,k] = 3
B[i-1,k] =
0
k = 0, so we’re DONE! k – wi = 0
for i = 1 to n O(n)
B[i,0] = 0
Repeat n times
for i = 1 to n
O(W)
for w = 0 to W
< the rest of the code >
Suppose you have a rod of length n, and you want to cut up the rod and sell the pieces in
a way that maximizes the total amount of money you get. A piece of length i is worth pi
dollars.
For example, if you have a rod of length 4, there are eight different ways to cut it, and the
best strategy is cutting it into two pieces of length 2, which gives you 10 dollars.
Exercise: How many ways are there to cut up a rod of length n?
Answer: 2 ^n−1 , because there are n − 1 places where we can choose to make cuts, and at
each place, we either make a cut or we do not make a cut.
Despite the exponentially large possibility space, we can use dynamic programming to write
an algorithm that runs in Θ(n^2).
Ahmet Unveren