0% found this document useful (0 votes)
4 views

Lecture9_IO_BLG336E_2022

This lecture covers dynamic programming with a focus on applications such as the Longest Common Subsequence (LCS) and the Knapsack Problem. It outlines the steps for applying dynamic programming, including identifying optimal substructure and formulating recursive solutions. The lecture also emphasizes the importance of overlapping sub-problems and provides examples relevant to bioinformatics.

Uploaded by

pearsonicin
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Lecture9_IO_BLG336E_2022

This lecture covers dynamic programming with a focus on applications such as the Longest Common Subsequence (LCS) and the Knapsack Problem. It outlines the steps for applying dynamic programming, including identifying optimal substructure and formulating recursive solutions. The lecture also emphasizes the importance of overlapping sub-problems and provides examples relevant to bioinformatics.

Uploaded by

pearsonicin
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 149

BLG 336E

Analysis of Algorithms II
Lecture 9:
Dynamic Programming II
DNA Sequencing, Knapsack Problem

1
Last time

• Dynamic programming is an algorithm design


paradigm.
• Basic idea:
• Identify optimal sub-structure
• Optimum to the big problem is built out of optima of small
sub-problems
• Take advantage of overlapping sub-problems
• Only solve each sub-problem once, then use it again and again
• Keep track of the solutions to sub-problems in a table
as you build to the final solution.
Today
• Examples of dynamic programming:
1. Longest common subsequence
2. Knapsack problem
• Two versions!
3. Independent sets in trees
• If we have time…
• (If not the slides will be there as a reference)
The goal of this lecture
• For you to get really bored of dynamic programming
Longest Common Subsequence
• How similar are these two species?

DNA: DNA:
AGCCCTAAGGGCTACCTAGCTT GACAGCCTACAAGCGTTAGCTTG
Longest Common Subsequence
• How similar are these two species?

DNA: DNA:
AGCCCTAAGGGCTACCTAGCTT GACAGCCTACAAGCGTTAGCTTG
• Pretty similar, their DNA has a long common subsequence:

AGCCTAAGCTTAGCTT
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.
We sometimes want to find these
• Applications in bioinformatics

• The unix command diff


• Merging in version control
• svn, git, etc…
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.
Step 1: Optimal substructure
Prefixes:

X A C G G T

Y A C G C T T A

Notation: denote this prefix ACGC by Y4

• Our sub-problems will be finding LCS’s of prefixes to X and Y.


• Let C[i,j] = length_of_LCS( Xi, Yj )
Optimal substructure ctd.
• Subproblem:
• finding LCS’s of prefixes of X and Y.

• Why is this a good choice?


• There’s some relationship between LCS’s of prefixes and
LCS’s of the whole things.
• These subproblems overlap a lot.

To see this formally, on to…


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.
• Our sub-problems will be finding
Two cases LCS’s of prefixes to X and Y.
• Let C[i,j] = length_of_LCS( Xi, Yj )
Case 1: X[i] = Y[j]
i These are
the same

Xi A C G G A
j

Yj A C G C T T A

Notation: denote this prefix ACGC by Y4

• Then C[i,j] = 1 + C[i-1,j-1].


• because LCS(Xi,Yj) = LCS(Xi-1,Yj-1) followed by A
• Our sub-problems will be finding
Two cases LCS’s of prefixes to X and Y.
• Let C[i,j] = length_of_LCS( Xi, Yj )
Case 2: X[i] != Y[j]
i These are
not the
same
Xi A C G G T
j

Yj A C G C T T A

Notation: denote this prefix ACGC by Y4

• Then C[i,j] = max{ C[i-1,j], C[i,j-1] }.


• either LCS(Xi,Yj) = LCS(Xi-1,Yj) and T is not involved,
• or LCS(Xi,Yj) = LCS(Xi,Yj-1) and A is not involved,
Recursive formulation
of the optimal solution X0
Yj A C G C T T A

Case 0

0 if 𝑖 = 0 or 𝑗 = 0
• 𝐶 𝑖, 𝑗 = ൞𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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 A
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.
LCS DP OMG BBQ
• LCS(X, Y):
• C[i,0] = C[0,j] = 0 for all i = 1,…,m, j=1,…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] }

0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = ൞ 𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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

C 0

X G 0

G 0

A 0
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = ൞𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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.
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 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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

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 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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

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 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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

G 0 1 2 2 3 That 3 must have come


from the 3 above it.
A 0 1 2 2 3
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = ൞𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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 This 3 came from that 2 –


0 1 2 2 3 we found a match!
G

A 0 1 2 2 3
0 if 𝑖 = 0 or 𝑗 = 0
𝐶 𝑖, 𝑗 = ൞𝐶 𝑖 − 1, 𝑗 − 1 + 1 if 𝑋 𝑖 = 𝑌 𝑗 and 𝑖, 𝑗 > 0
max 𝐶 𝑖, 𝑗 − 1 , 𝐶 𝑖 − 1, 𝑗 if 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 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 𝑋 𝑖 ≠ 𝑌 𝑗 and 𝑖, 𝑗 > 0
This gives an algorithm to recover the actual LCS
not just its length

• It runs in time O(n + m)


• We walk up and left in an n-by-m array
• We can only do that for n + m steps.
• So actually recovering the LCS from the table is
much faster than building the table was.
• We can find LCS(X,Y) in time O(mn).
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.
This pseudocode actually isn’t so bad

• If we are only interested in the length of the LCS:


• Since we go across the table one-row-at-a-time, we can only
keep two rows if we want.
• If we want to recover the LCS, we need to keep the whole
table.

• Can we do better than O(mn) time?


• A bit better.
• By a log factor or so.
• But doing much better (polynomially better) is an open
problem!
• If you can do it let me know :D
What have we learned?
• We can find LCS(X,Y) in time O(nm)
• if |Y|=n, |X|=m

• We went through the steps of coming up with a


dynamic programming algorithm.
• We kept a 2-dimensional table, breaking down the
problem by decrementing the length of X and Y.
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

• And we have a knapsack: Capacity: 10


• it can only carry so much weight:
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
Some notation

Item:

Weight: w1 w2 w3 … wn
Value: v1 v2 v3 vn

Capacity: W
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.
Optimal substructure
• Sub-problems:
• Unbounded Knapsack with a smaller knapsack.

First solve the


problem for Then larger Then larger
small knapsacks knapsacks knapsacks
Optimal substructure item i

• Suppose this is an optimal solution for capacity x:

Weight wi
Value vi
Capacity x
• Then this optimal for capacity x - wi: Value V

If I could do better than the second solution, Capacity x – wi


then adding a turtle to that improvement Value V - vi
would improve the first solution.
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.
Recursive relationship
• Let K[x] be the optimal value for capacity x.

K[x] = maxi { + }
The maximum is over Optimal way to The value of
all i so that 𝑤𝑖 ≤ 𝑥. fill the smaller item i.
knapsack

K[x] = maxi { K[x – wi] + vi }

• (And K[x] = 0 if the maximum is empty).


• That is, there are no i so that 𝑤𝑖 ≤ 𝑥
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.
Let’s write a bottom-up DP algorithm
• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
• if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• return K[W]

Running time: O(nW)


K[x] = maxi { + }
Why does this work?
= maxi { K[x – wi] + vi } Because our recursive relationship makes sense.
Can we do better?
• We only need log(W) bits to write down the input W
and to write down all the weights.
• Maybe we could have an algorithm that runs in time
O(nlog(W)) instead of O(nW)?
• Or even O( n1000000 log1000000(W) )?

• Open problem!
• (But probably the answer is no…otherwise P = NP)
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.
Let’s write a bottom-up DP algorithm
• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
• if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• return K[W]

K[x] = maxi { + }

= maxi { K[x – wi] + vi }


Let’s write a bottom-up DP algorithm
• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• ITEMS[0] = ∅
• for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
• if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• If K[x] was updated:
• ITEMS[x] = ITEMS[x – wi] ∪ { item i }
• return ITEMS[W]

K[x] = maxi { + }

= maxi { K[x – wi] + vi }


• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• ITEMS[0] = ∅
Example • for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
0 1 2 3 4 • if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• If K[x] was updated:
K 0 • ITEMS[x] = ITEMS[x – wi] ∪ { item
• return ITEMS[W]
ITEMS

Item:
Weight: 1 2 3
Value: 1 4 6

Capacity: 4
• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• ITEMS[0] = ∅
Example • for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
0 1 2 3 4 • if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• If K[x] was updated:
K 0 1 • ITEMS[x] = ITEMS[x – wi] ∪ { item
• return ITEMS[W]
ITEMS

Item:
Weight: 1 2 3
Value: 1 4 6

ITEMS[1] = ITEMS[0] +

Capacity: 4
• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• ITEMS[0] = ∅
Example • for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
0 1 2 3 4 • if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• If K[x] was updated:
K 0 1 2 • ITEMS[x] = ITEMS[x – wi] ∪ { item
• return ITEMS[W]
ITEMS

Item:
Weight: 1 2 3
Value: 1 4 6

ITEMS[2] = ITEMS[1] +

Capacity: 4
• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• ITEMS[0] = ∅
Example • for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
0 1 2 3 4 • if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• If K[x] was updated:
K 0 1 4 • ITEMS[x] = ITEMS[x – wi] ∪ { item
• return ITEMS[W]
ITEMS

Item:
Weight: 1 2 3
Value: 1 4 6

ITEMS[2] = ITEMS[0] +

Capacity: 4
• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• ITEMS[0] = ∅
Example • for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
0 1 2 3 4 • if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• If K[x] was updated:
K 0 1 4 5 • ITEMS[x] = ITEMS[x – wi] ∪ { item
• return ITEMS[W]
ITEMS

Item:
Weight: 1 2 3
Value: 1 4 6

ITEMS[3] = ITEMS[2] +

Capacity: 4
• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• ITEMS[0] = ∅
Example • for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
0 1 2 3 4 • if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• If K[x] was updated:
K 0 1 4 6 • ITEMS[x] = ITEMS[x – wi] ∪ { item
• return ITEMS[W]
ITEMS

Item:
Weight: 1 2 3
Value: 1 4 6

ITEMS[3] = ITEMS[0] +

Capacity: 4
• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• ITEMS[0] = ∅
Example • for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
0 1 2 3 4 • if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• If K[x] was updated:
K 0 1 4 6 7 • ITEMS[x] = ITEMS[x – wi] ∪ { item
• return ITEMS[W]
ITEMS

Item:
Weight: 1 2 3
Value: 1 4 6

ITEMS[4] = ITEMS[3] +

Capacity: 4
• UnboundedKnapsack(W, n, weights, values):
• K[0] = 0
• ITEMS[0] = ∅
Example • for x = 1, …, W:
• K[x] = 0
• for i = 1, …, n:
0 1 2 3 4 • if 𝑤𝑖 ≤ 𝑥:
• 𝐾 𝑥 = max{ 𝐾 𝑥 , 𝐾 𝑥 − 𝑤𝑖 + 𝑣𝑖 }
• If K[x] was updated:
K 0 1 4 6 8 • ITEMS[x] = ITEMS[x – wi] ∪ { item
• return ITEMS[W]
ITEMS

Item:
Weight: 1 2 3
Value: 1 4 6

ITEMS[4] = ITEMS[2] +

Capacity: 4
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.
What have we learned?
• We can solve unbounded knapsack in time O(nW).
• If there are n items and our knapsack has capacity W.

• We again went through the steps to create DP


solution:
• We kept a one-dimensional table, creating smaller
problems by making the knapsack smaller.
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
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.
Optimal substructure: try 1
• Sub-problems:
• Unbounded Knapsack with a smaller knapsack.

First solve the


problem for Then larger Then larger
small knapsacks knapsacks knapsacks
This won’t quite work…
• We are only allowed one copy of each item.
• The sub-problem needs to “know” what items
we’ve used and what we haven’t.

I can’t use
any turtles…
Optimal substructure: try 2
• Sub-problems:
• 0/1 Knapsack with fewer items.

First solve the


problem with
few items
We’ll still increase the size of the knapsacks.
Then more
items

Then yet
more
items
Our sub-problems:
• Indexed by x and j

First j items Capacity x


Two cases item j

• Case 1: Optimal solution for j items does not use item j.


• Case 2: Optimal solution for j items does use item j.

First j items Capacity x


Two cases item j

• Case 1: Optimal solution for j items does not use item j.

Capacity x
Value V
First j items Use only the first j items

• Then this is an optimal solution for j-1 items:

Capacity x
Value V
First j-1 items Use only the first j-1 items.
Two cases item j

• Case 2: Optimal solution for j items uses 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 – wi
Value V – vi
First j-1 items Use only the first j-1 items.
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.
Recursive relationship
• Let K[x,j] be the optimal value for:
• capacity x,
• with j items.

K[x,j] = max{ K[x, j-1] , K[x – wj, j-1] + vj }


Case 1 Case 2

• (And K[x,0] = 0 and K[0,j] = 0).


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.
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]

Running time O(nW)


• 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:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=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: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

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: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

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: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1
j=1

0 1
j=2

0
j=3

Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1
j=1

0 1
j=2

0 1
j=3

Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1 0
j=1

0 1
j=2

0 1
j=3

Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1 1
j=1

0 1
j=2

0 1
j=3

Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1 1
j=1

0 1 1
j=2

0 1
j=3

Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

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: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

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: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1 1 0
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: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1 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: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1 1 1
j=1

0 1 4 1
j=2

0 1 4
j=3

Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1 1 1
j=1

0 1 4 5
j=2

0 1 4
j=3

Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1 1 1
j=1

0 1 4 5
j=2

0 1 4 5
j=3

Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

0 1 1 1
j=1

0 1 4 5
j=2

0 1 4 6
j=3

Item:
current relevant Weight: 1 2 3
entry previous entry Value: 1 4 6 Capacity: 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
• for x = 1,…,W:
Example • for j = 1,…,n:
• K[x,j] = K[x, j-1]
• if wj ≤ x:
x=0 x=1 x=2 x=3 • K[x,j] = max{ K[x,j],
K[x – wj, j-1] + vj }
0 0 0 0 • return K[W,n]
j=0

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: 3
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.
What have we learned?
• We can solve 0/1 knapsack in time O(nW).
• If there are n items and our knapsack has capacity W.

• We again went through the steps to create DP


solution:
• We kept a two-dimensional table, creating smaller
problems by restricting the set of allowable items.
Question
• How did we know which substructure to use in
which variant of knapsack? Answer in retrospect:

This one made sense for


unbounded knapsack
because it doesn’t have
any memory of what
items have been used.

vs.
In 0/1 knapsack, we
can only use each item
once, so it makes sense
to leave out one item
at a time.

Operational Answer: try some stuff, see what works!


Example 3: Independent Set
if we still have time
2

1
2

An independent set 3
is a set of vertices • Given a graph with
so that no pair has weights on the
an edge between vertices…
them.
5 • What is the
1 independent set with
the largest weight?
Actually this problem is NP-complete.
So we are unlikely to find an efficient algorithm
• But if we also assume that the graph is a tree…

2 3
3 5

A tree is a
connected
2 3 1 graph with no
cycles.
5

2 5

Problem:
find a maximal independent set in a tree (with vertex weights).
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.
Optimal substructure
• Subtrees are a natural candidate.
• There are two cases:
1. The root of this tree is in a not in
a maximal independent set.
2. Or it is.
Case 1:
the root is not in an maximal independent set
• Use the optimal solution
from these smaller problems.
Case 2:
the root is in an maximal independent set
• Then its children can’t be.
• Below that, use the optimal
solution from these smaller
subproblems.
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.
Recursive formulation: try 1
• Let A[u] be the weight of a maximal independent set
in the tree rooted at u.

•𝐴𝑢 =
σ𝑣∈𝑢.children 𝐴[𝑣]
max ൞
weight 𝑢 + σ𝑣∈𝑢.grandchildren 𝐴[𝑣]

When we implement this, how do


we keep track of this term?
Recursive formulation: try 2
Keep two arrays!
• Let A[u] be the weight of a maximal independent set
in the tree rooted at u.
• Let B[u] = σ𝑣∈𝑢.children 𝐴[𝑣]

σ𝑣∈𝑢.children 𝐴[𝑣]
• 𝐴 𝑢 = max ൞
weight 𝑢 + σ𝑣∈𝑢.children 𝐵[𝑣]
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.
A top-down DP algorithm
• MIS_subtree(u):
• if u is a leaf:
• A[u] = weight(u)
• B[u] = 0
• else:
• for v in u.children:
• MIS_subtree(v)
• 𝐴 𝑢 = max{ σ𝑣∈𝑢.children 𝐴[𝑣] , weight 𝑢 + σ𝑣∈𝑢.children 𝐵[𝑣] }
• B 𝑢 = σ𝑣∈𝑢.children 𝐴[𝑣]

Running time?
• MIS(T): • We visit each vertex once, and at
every vertex we do O(1) work:
• MIS_subtree(T.root) • Make a recursive call
• return A[T.root] • look stuff up in tables
• Running time is O(|V|)
Why is this different from divide-and-conquer?
That’s always worked for us with tree problems before…

• MIS_subtree(u):
• if u is a leaf:
• return weight(u)
• else:
• for v in u.children:
• MIS_subtree(v)
• return max{ σ𝑣∈𝑢.children MIS_subtree(𝑣) ,

weight 𝑢 + σ𝑣∈𝑢.grandchildren MIS_subtree(𝑣) }

• MIS(T):
• return MIS_subtree(T.root)
Why is this different from divide-and-conquer?
That’s always worked for us with tree problems before…

How often would we ask


about the subtree rooted
here?

Once for this node


and once for this one.

But we then ask


about this node
twice, here and here.

This will blow up exponentially


without using dynamic
programming to take advantage
of overlapping subproblems.
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.
What have we learned?
• We can find maximal independent sets in trees in
time O(|V|) using dynamic programming!

• For this example, it was natural to implement our


DP algorithm in a top-down way.
Recap
• Today we saw examples of how to come up with
dynamic programming algorithms.
• Longest Common Subsequence
• Knapsack two ways
• (If time) maximal independent set in trees.
• There is a recipe for dynamic programming
algorithms.
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.
Recap
• Today we saw examples of how to come up with
dynamic programming algorithms.
• Longest Common Subsequence
• Knapsack two ways
• (If time) maximal independent set in trees.
• There is a recipe for dynamic programming
algorithms.
• Sometimes coming up with the right substructure
takes some creativity
6. DYNAMIC PROGRAMMING

‣ weighted interval scheduling


‣ segmented least squares
‣ knapsack problem
‣ RNA secondary structure

SECTION 6.4
Knapsack problem

Goal. Pack knapsack so as to maximize total value of items taken.


・There are n items: item i provides value vi > 0 and weighs wi > 0.
・Value of a subset of items = sum of values of individual items.
・Knapsack has weight limit of W.
Ex. The subset { 1, 2, 5 } has value $ 3 5 (and weight 10).
Ex. The subset { 3, 4 } has value $ 4 0 (and weight 11).

Assumption. All values and weights are integral.


i vi wi
1 $1 1 kg
weights and values
2 $6 2 kg can be arbitrary
positive integers
3 $18 5 kg
4 $22 6 kg
5 $28 7 kg

Creative Commons Attribution-Share Alike 2.5


knapsackinstance
by Dake (weightlimit W= 1 1 ) 31
Dynamic programming: quiz 2

Which algorithm solves knapsack problem?

A. Greedy-by-value: repeatedly add item with maximum vi.

B. Greedy-by-weight: repeatedly add item with minimum wi.

C. Greedy-by-ratio: repeatedly add item with maximum ratio vi /wi.

D. None of the above.

i vi wi
1 $1 1 kg
2 $6 2 kg
3 $18 5 kg
4 $22 6 kg
5 $28 7 kg

knapsackinstance
Creative Commons Attribution-Share Alike 2.5
(weightlimit W= 1 1 )
by Dake
32
Dynamic programming: quiz 3

Whichsubproblems?

A. OPT(w) = optimal value of knapsack problem with weight limit w.

B. OPT(i) = optimal value of knapsack problem with items 1, …, i.

C. OPT(i, w) = optimal value of knapsack problem with items 1, …, i


subject to weight limit w.

D. Any of the above.

33
Dynamic programming: two variables

3
4
Knapsack problem: bottom-up dynamic programming

KNAPSACK(n, W, w1, …, wn, v1, …, vn )

FOR w = 0 TO W
M[0, w]  0.

previously computed values


FOR i = 1 TO n
FOR w = 0 TO W
IF (wi > w) M[i, w ]  M[i – 1, w].
ELSE M[i, w ]  max { M[i – 1, w], vi + M[i – 1, w – wi] }.

RETURN M[n, W]. 3


5
Knapsack problem: bottom-up dynamic programming demo

3
6
Knapsack Problem

Truck – 10t capacity

Optimum cargo combination:

•Item 1: $5 (3t)
•Item 2: $7 (4t)
•Item 3: $8 (5t)
Knapsack Problem
Output function f(i,w)

Optimum output of a combination of items 1
to i with a cumulated weight of w or less.

•Item 1: x1=$5 ; w1=3t


•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem
Output function f(i,w)

f(i,w)=Max[ xi + f(i,w-wi) ; f(i-1,w) ]

ONE Item i + optimum NO Item i + optimum


combination of weight combination items 1 to
w-wi i-1
Knapsack Problem
Table
1 2 3 4 5 6 7 8 9 10 W
1
2
3

f(i,w)
•Item 1: x1=$5 ; w1=3t
i •Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
•Item 1: x1=$5 ; w1=3t
•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem
Table
1 2 3 4 5 6 7 8 9 10 W
1 Using only item 1
2
3

i
•Item 1: x1=$5 ; w1=3t
•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem
Table
1 2 3 4 5 6 7 8 9 10 W
1
2 Using only item 1 & 2
3

i
•Item 1: x1=$5 ; w1=3t
•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem
Table
1 2 3 4 5 6 7 8 9 10 W
1
2
3 Using items 1, 2 & 3

i
•Item 1: x1=$5 ; w1=3t
•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem
Table
1 2 3 4 5 6 7 8 9 10 W
1 0 0 5 5 5 10
2
3

2 items n°1
0 items n°1 1 items n°1
2 w1 = 6
w1 = 3
•Item 1: x1=$5 ; w1=3t
•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem
Table
1 2 3 4 5 6 7 8 9 10 w – w2 =
5–4=1
1 0 0 5 5 5 10 10 10 15 15
2 0 0 5 7
3
+ x2 (= 7)

f(i,w)=Max[ xi + f(i,w-wi) ; f(i-1,w) ]


•Item 1: x1=$5 ; w1=3t
•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem
Table
1 2 3 4 5 6 7 8 9 10
1 0 0 5 5 5 10 10 10 15 15
2 0 0 5 7 7
3
+ x2 (= 7)

f(i,w)=Max[ xi + f(i,w-wi) ; f(i-1,w) ]


•Item 1: x1=$5 ; w1=3t
•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem
Table
1 2 3 4 5 6 7 8 9 10 w – w2 =
6–4=2
1 0 0 5 5 5 10 10 10 15 15
2 0 0 5 7 7
3
+ x2 (= 7)

f(i,w)=Max[ xi + f(i,w-wi) ; f(i-1,w) ]


•Item 1: x1=$5 ; w1=3t
•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem
Table
1 2 3 4 5 6 7 8 9 10
1 0 0 5 5 5 10 10 10 15 15
2 0 0 5 7 7 10
3
+ x2 (= 7)

f(i,w)=Max[ xi + f(i,w-wi) ; f(i-1,w) ]


•Item 1: x1=$5 ; w1=3t
•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem

COMPLETED TABLE
1 2 3 4 5 6 7 8 9 10

1 0 0 5 5 5 10 10 10 15 15

2 0 0 5 7 7 10 12 14 15 17

3 0 0 5 7 8 10 12 14 15 17
•Item 1: x1=$5 ; w1=3t
•Item 2: x2=$7 ; w2=4t
•Item 3: x3=$8 ; w3=5t
Knapsack Problem
Path
1 2 3 4 5 6 7 8 9 10

1 0 0 5 5 5 10 10 10 15 15

2 0 0 5 7 7 10 12 14 15 17

3 0 0 5 7 8 10 12 14 15 17

Item 1 Item 1 Item 2

Optimal: 2 x Item 1 + 1 x Item 2


Knapsack problem: running time

Theorem. The DP algorithm solves the knapsack problem with n items


and maximum weight W in Θ(n W) time and Θ(n W) space.
Pf. weights are integers

・Takes O(1) time per table entry. between 1 and W

・There are Θ(n W) table entries.


・After computing optimal values, can trace back to find solution:
OPT(i, w) takes item i iff M [i, w] > M [i – 1, w]. ▪

Remarks.
・Algorithm depends critically on assumption that weights are integral.
3
7

・Assumption that values are integral was not used.


Knapsack Problem: Bottom-Up

Knapsack. Fill up an n-by-W array.

Input: n, w1,…,wN, v1,…,vN

for w = 0 to W
M[0, w] = 0

for i = 1 to n
for w = 1 to W
if (wi > w)
M[i, w] = M[i-1, w]
else
M[i, w] = max {M[i-1, w], vi + M[i-1, w-wi ]}

return M[n, W]

131
Knapsack Algorithm

W+1

0 1 2 3 4 5 6 7 8 9 10 11

 0 0 0 0 0 0 0 0 0 0 0 0
{1} 0 1 1 1 1 1 1 1 1 1 1 1

n+1 { 1, 2 } 0 1 6 7 7 7 7 7 7 7 7 7
{ 1, 2, 3 } 0 1 6 7 7 18 19 24 25 25 25 25
{ 1, 2, 3, 4 } 0 1 6 7 7 18 22 24 28 29 29 40
{ 1, 2, 3, 4, 5 } 0 1 6 7 7 18 22 28 29 34 34 40

Item Value Weight


1 1 1
OPT: { 4, 3 } 2 6 2
value = 22 + 18 = 40
W = 11 3 18 5
4 22 6
5 28 7
132
Dynamic programming: quiz 4

Does there exist a poly-time algorithm for the knapsackproblem?

A. Yes, because the DP algorithm takes Θ(n W) time. “pseudo-polynomial”

B. No, because Θ(n W) is not a polynomial function of the input size.

C. No, because the problem is NP-hard.

D. Unknown.

equivalent to P≠ NPconjecture
because knapsack problem is NP-hard

38
COIN CHANGING

Problem. Given n coin denominations { c1, c2, …, cn } and a target value V,


find the fewest coins needed to make change for V (or report impossible).

Recall. Greedy cashier’s algorithm is optimal for U.S. coin denominations,


but not for arbitrary coin denominations.

Ex. { 1, 10, 21, 34, 70, 100, 350, 1295, 1 5 0 0 }.


Optimal. 1 4 0 ¢ = 7 0 + 70.

39
6. DYNAMIC PROGRAMMING I

‣ weighted interval scheduling


‣ segmented least squares
‣ knapsack problem
‣ RNA secondary structure

SECTION 6.5
RNA secondary structure

RNA. String B = b1b2…bn over alphabet { A, C, G, U}.

Secondary structure. RNA is single-stranded so it tends to loop back and


form base pairs with itself. This structure is essential for understanding
behavior of molecule.

C A

A A

A U G C
base
C G U A A G

G
U A U U A
base pair G
A C G C U
G

C G C G A G C

G
A U

RNAsecondarystructure forGUCGAUUGAGCGAAUGUAACAACGUGGCUACGGCGAGA
42
RNA secondary structure

Secondary structure. A set of pairs S = { (bi, bj) } that satisfy:


・[Watson–Crick] S is a matching and each pair in S is a Watson–Crick
complement: A–U, U–A, C–G, or G–C.

G G

C U

C G 4
A C G U 3G G C C A U

base pair Sis not asecondarystructure


in secondary structure A C
(C-Ais not avalid Watson-Crick pair)

U A

B =ACGUGGCCCAU
S = { (b1, b10), (b2, b9), (b3, b8) }
RNA secondary structure

Secondary structure. A set of pairs S = { (bi, bj) } that satisfy:


・[Watson–Crick] S is a matching and each pair in S is a Watson–Crick
complement: A–U, U–A, C–G, or G–C.
・[No sharp turns] The ends of each pair are separated by at least 4
intervening bases. If (bi, bj)  S, then i < j – 4.

G G

C G
4
4

A U G G G G C A U
A U

Sis not asecondarystructure


U A (≤4 intervening bases between GandC)

B =AUGGGGCAU
S = { (b1, b10), (b2, b9), (b3, b8) }
RNA secondary structure

Secondary structure. A set of pairs S = { (bi, bj) } that satisfy:


・[Watson–Crick] S is a matching and each pair in S is a Watson–Crick
complement: A–U, U–A, C–G, or G–C.
・[No sharp turns] The ends of each pair are separated by at least 4
intervening bases. If (bi, bj)  S, then i < j – 4.

・[Non-crossing] If (bi, bj) and (bk, bℓ) are two pairs in S, then we cannot
have i < k < j < ℓ.

G G

C U

C U 4
5

A G
A G U U G G C C A U

U A Sis not asecondarystructure (G-Cand U-A


cross)
B = ACUUGGCCAU
S = { (b1, b10), (b2, b8), (b3, b9) }
RNA secondary structure

Secondary structure. A set of pairs S = { (bi, bj) } that satisfy:


・[Watson–Crick] S is a matching and each pair in S is a Watson–Crick
complement: A–U, U–A, C–G, or G–C.
・[No sharp turns] The ends of each pair are separated by at least 4
intervening bases. If (bi, bj)  S, then i < j – 4.

・[Non-crossing] If (bi, bj) and (bk, bℓ) are two pairs in S, then we cannot
have i < k < j < ℓ.

G G

C U

C G 4
6

A U
A U G U G G C C A U

Sis asecondarystructure (with3base


U A
pairs)
B = AUGUGGCCAU
S = { (b1, b10), (b2, b9), (b3, b8) }
RNA secondary structure

Secondary structure. A set of pairs S = { (bi, bj) } that satisfy:


・[Watson–Crick] S is a matching and each pair in S is a Watson–Crick
complement: A–U, U–A, C–G, or G–C.
・[No sharp turns] The ends of each pair are separated by at least 4
intervening bases. If (bi, bj)  S, then i < j – 4.

・[Non-crossing] If (bi, bj) and (bk, bℓ) are two pairs in S, then we cannot
have i < k < j < ℓ.

Free-energy hypothesis. RNA molecule will form the secondary structure


with the minimum total free energy.

approximate by number of base pairs


(more base pairs  lower free energy)

Goal. Given an RNA molecule B = b1b2…bn, find a secondary structure S


that maximizes the number of base pairs.
47
Dynamic programming: quiz 5

Is the followinga secondary structure?

A. Yes.

B. No, violates Watson–Crick condition.

C. No, violates no-sharp-turns condition.

D. No, violates no-crossing condition.

G C

C G U A A G

A U U A
G
G C U
G

C G A G C

A U

G 48
Dynamic programming: quiz 6

Which subproblems?
A. OPT(j) = max number of base pairs in secondary structure
of the substring b1b2 … bj.

B. OPT(j) = max number of base pairs in secondary structure


of the substring bj bj+1 … bn.

C. Either A or B.

D. Neither A nor B.

49
RN A secondary structure: subproblems

First attempt. OPT(j) = maximum number of base pairs in a secondary


structure of the substring b1b2 … bj.

Goal. OPT(n).

matchbases bt andbn
Choice. Match bases bt and bj.

1 t j last base

Difficulty. Results in two subproblems (but one of wrong form).


・ Find secondary structure in b1b2 … bt–1. OPT(t–1)
bt+1bt+2 … bj–1.
・Find secondary structure in need more subproblems
(first base no longer b1)

50
Dynamic programming over intervals

Def. OPT(i, j) = maximum number of base pairs in a secondary structure


of the substring bi bi+1 … bj.

Case 1. If i ≥ j – 4.
・OPT(i, j ) = 0 by no-sharp-turns condition.

Case 2. Base bj is not involved in a pair.


・OPT(i, j )= OPT(i, j – 1).

Case 3. Base bj pairs with bt for some i ≤ t < j – 4.


・Non-crossing condition decouples resulting two subproblems.
・OPT(i, j ) = 1 + max t { OPT(i, t – 1) + OPT(t + 1, j – 1) }.
matchbases bj andbt
take max over t such that i ≤ t < j – 4 and
bt and bj are Watson–Crick complements

i t j 51
Dynamic programming: quiz 7

52
Bottom-up dynamic programming over intervals

Q. In which order to solve the subproblems?


A. D o shortest intervals first—increasing order of j− i.

RNA-SECONDARY-STRUCTURE(n, b1, …, bn ) j
6 7 8 9 10
FOR k = 5 TO n – 1 4 0 0 0
all needed values
FOR i = 1 TO n – k are already computed 3 0 0
i
j  i + k. 2 0

Compute M[i, j] using formula. 1

RETURN M[1, n]. orderin whichto solve subproblems


5
3

Theorem. The DP algorithm solves the RNA secondary structure problem in


O(n3) time and O(n2) space.
Dynamic programming summary

typically, only a polynomial


Outline. number of subproblems

・Define a collection of subproblems.


・Solution to original problem can be
computed from subproblems.

・Natural ordering of subproblems from


“smallest” to “largest” that enables
determining a solution to a subproblem
from solutions to smaller subproblems.
Techniques.
・Binary choice: weighted interval scheduling.
・Multiway choice: segmented least squares. 5

・Adding a new variable: knapsack problem.


4

・Intervals: RNA secondary structure.


Top-down vs. bottom-up dynamic programming. Opinions differ.
NEXT LECTURE

• Min-cut
• Karger’s Algorithm

149

You might also like