0% found this document useful (0 votes)
7 views51 pages

14 dp4

The document discusses the concept of the Longest Increasing Subsequence (LIS) using dynamic programming on trees, outlining the necessary conditions for including elements in the subsequence. It presents a recurrence relation for calculating LIS and provides a pseudocode example for implementation. Additionally, it touches on the Subset Sum problem, illustrating how to determine if a subset of an array sums to a specific target.

Uploaded by

Tanmay Tripathi
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)
7 views51 pages

14 dp4

The document discusses the concept of the Longest Increasing Subsequence (LIS) using dynamic programming on trees, outlining the necessary conditions for including elements in the subsequence. It presents a recurrence relation for calculating LIS and provides a pseudocode example for implementation. Additionally, it touches on the Subset Sum problem, illustrating how to determine if a subset of an array sums to a specific target.

Uploaded by

Tanmay Tripathi
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/ 51

Dynamic Programming

on Trees
Longest Increasing Subsequence
0 1 2 3 4 5 6 7

5 -6 3 6 -5 2 8 10

Longest set of (not necessarily consecutive) elements that are increasing

5 is optimal for the array above


(indices 1,2,3,6,7; elements −6,3,6,8,10)

For simplicity – assume all array elements are distinct.


Longest Increasing Subsequence
What do we need to know to decide on element 𝑖?

Is it allowed?
Will the sequence still be increasing if it’s included?

Still thinking right to left --


Two indices: index we’re looking at, and index of upper bound on
elements (i.e. the value we need to decide if we’re still increasing).
Recurrence
0 1 2 3 4 5 6 7

5 -6 3 6 -5 2 8 10
Recursive call is best value in this area Current 𝑖 Not yet processed.

Need recursive answer to the left


Currently processing 𝑖
Recursive calls to the left are needed to know optimum from 1 … 𝑖
Will move 𝑖 to the right in our iterative algorithm
Longest Increasing Subsequence
𝐿𝐼𝑆 𝑖, 𝑗 is “Number of elements of the maximum increasing subsequence from
1, … , 𝑖 where every element of the sequence is at most 𝐴[𝑗]”
Need a recurrence
0 if 𝑖 < 0
𝕀[𝐴 𝑖 ≤ 𝐴 𝑗 ] if 𝑖 = 0
𝐿𝐼𝑆 𝑖, 𝑗 =
𝐿𝐼𝑆 𝑖 − 1, 𝑗 if 𝐴 𝑖 > 𝐴 𝑗
max 1 + 𝐿𝐼𝑆 𝑖 − 1, 𝑖 , 𝐿𝐼𝑆 𝑖 − 1, 𝑗 otherwise
If 𝐴 𝑖 > 𝐴[𝑗] element 𝑖 cannot be included in an increasing subsequence where
every element is at most 𝐴[𝑗]. So taking the largest among the first 𝑖 − 1 suffices.
If 𝐴 𝑖 ≤ 𝐴[𝑗], then if we include 𝑖, we may include elements to the left only if they
are less than 𝐴[𝑖] (since 𝐴 𝑖 will now be the last, and therefore largest, of elements
1 … 𝑖. If we don’t include 𝑖 we want the maximum increasing subsequence among
1 … 𝑖 − 1.
Longest Increasing Subsequence
0 if 𝑖 < 0
𝕀[𝐴 𝑖 ≤ 𝐴 𝑗 ] if 𝑖 = 0
𝐿𝐼𝑆 𝑖, 𝑗 =
𝐿𝐼𝑆 𝑖 − 1, 𝑗 if 𝐴 𝑖 > 𝐴 𝑗
max 1 + 𝐿𝐼𝑆 𝑖 − 1, 𝑖 , 𝐿𝐼𝑆 𝑖 − 1, 𝑗 otherwise

Memoization structure? 𝑛 × 𝑛 array.


Filling order?
LIS
𝑗
0, 5 1, −6 2, 3 3, 6 4, −5 5, 2 6, 8 7, 10
0, 5
1, −6
2, 3
3, 6
𝑖
4, −5
5, 2
6, 8
7, 10
𝐿𝐼𝑆 1,0 𝐴 1 < 𝐴[0] not allowed:
LIS Take 𝐿𝐼𝑆(0,0)

𝑗
0, 5 1, −6 2, 3 3, 6 4, −5 5, 2 6, 8 7, 10
0, 5 1 0 0 1 0 0 1 1
1, −6 1
2, 3
3, 6
𝑖
4, −5
5, 2
6, 8
7, 10
𝐿𝐼𝑆 1,1 𝐴 1 ≥ 𝐴[1] can add, 1 + 𝐿𝐼𝑆(0,1) or 𝐿𝐼𝑆(0,1)
LIS
𝑗
0, 5 1, −6 2, 3 3, 6 4, −5 5, 2 6, 8 7, 10
0, 5 1 0 0 1 0 0 1 1
1, −6 1 1
2, 3
3, 6
𝑖
4, −5
5, 2
6, 8
7, 10
𝐿𝐼𝑆 1,2 𝐴 1 ≤ 𝐴[2] allowed to add:
LIS 1 + 𝐿𝐼𝑆 0,1 or 𝐿𝐼𝑆(0,2)

𝑗
0, 5 1, −6 2, 3 3, 6 4, −5 5, 2 6, 8 7, 10
0, 5 1 0 0 1 0 0 1 1
1, −6 1 1 1
2, 3
3, 6
𝑖
4, −5
5, 2
6, 8
7, 10
𝐿𝐼𝑆 2,0 𝐴 2 ≤ 𝐴 0 allowed to add
LIS 1 + 𝐿𝐼𝑆(1,2) or 𝐿𝐼𝑆(1,0)

𝑗
0, 5 1, −6 2, 3 3, 6 4, −5 5, 2 6, 8 7, 10
0, 5 1 0 0 1 0 0 1 1
1, −6 1 1 1 1 1 1 1 1
2, 3 2
3, 6
𝑖
4, −5
5, 2
6, 8
7, 10
LIS
𝑗
0, 5 1, −6 2, 3 3, 6 4, −5 5, 2 6, 8 7, 10
0, 5 1 0 0 1 0 0 1 1
1, −6 1 1 1 1 1 1 1 1
2, 3 2 1 2 2 1 1 2 2

𝑖 3, 6 2 1 2 3 1 1 3 3
4, −5 2 1 2 3 2 2 3 3
5, 2 3 1 3 3 2 3 3 3
6, 8 3 1 3 3 2 3 4 4
7, 10 3 1 3 3 2 3 4 5
pseudocode
//real code snippet that actually generated the table on the last slide
for(int j=0; j < n; j++){
vals[0][j] = (A[0] <= A[j]) ? 1 : 0;
}
for(int i = 1; i < 8; i++){
for(int j = 0; j < n; j++){
if(A[i] > A[j])
vals[i][j] = vals[i-1][j];
else{
vals[i][j] = Math.max(1+vals[i-1][i], vals[i-1][j]);
}
}
}
Longest Increasing Subsequence
0 if 𝑖 < 0
𝕀[𝐴 𝑖 ≤ 𝐴 𝑗 ] if 𝑖 = 0
𝐿𝐼𝑆 𝑖, 𝑗 =
𝐿𝐼𝑆 𝑖 − 1, 𝑗 if 𝐴 𝑖 > 𝐴 𝑗
max 1 + 𝐿𝐼𝑆 𝑖 − 1, 𝑖 , 𝐿𝐼𝑆 𝑖 − 1, 𝑗 otherwise

Memoization structure? 𝑛 × 𝑛 array.


Filling order?
Outer loop: increasing 𝑖
Inner loop: increasing 𝑗
Recurrence
0 1 2 3 4 5 6 7

5 -6 3 6 -5 2 8 10
Not yet processed. Current 𝑖 Recursive call is best value in this area

Need recursive answer to the right


Currently processing 𝑖
Recursive calls to the right are needed to know optimum from 𝑖 … 𝑛
Will move 𝑖 to the left in our iterative algorithm
Recurrence
0 1 2 3 4 5 6 7

5 -6 3 6 -5 2 8 10
Not yet processed. Current 𝑖 Recursive call is best value in this area

Fill out the poll everywhere for Try to write a different


Activity Credit! recurrence for longest
Go to pollev.com/cse417 and login increasing subsequence.
with your UW identity
Longest Increasing Subsequence
Think left-to-right instead of right-to-left

𝐿𝐼𝑆𝐴𝑙𝑡 𝑖, 𝑗 is “Number of elements of the maximum increasing


subsequence from 𝑖, … , 𝑛 where smallest element of the sequence is 𝐴[𝑗]”

0 if 𝑖 > 𝑛 𝑜𝑟 𝑗 > 𝑛
𝐿𝐼𝑆𝐴𝑙𝑡 𝑖, 𝑗 = ቐ𝐿𝐼𝑆 𝑖 + 1, 𝑗 if 𝐴 𝑖 > 𝐴[𝑗]
max{1 + 𝐿𝐼𝑆 𝑖 + 1, 𝑖 , 𝐿𝐼𝑆 𝑖 + 1, 𝑗 } o/w
Longest Increasing Subsequence
𝐿𝐼𝑆𝐴𝑙𝑡 𝑖, 𝑗 is “Number of elements of the maximum increasing
subsequence from 𝑖, … , 𝑛 where smallest element of the sequence is 𝐴[𝑗]”

0 if 𝑖 > 𝑛 𝑜𝑟 𝑗 > 𝑛
𝐿𝐼𝑆𝐴𝑙𝑡 𝑖, 𝑗 = ቐ 𝐿𝐼𝑆𝐴𝑙𝑡 𝑖 + 1, 𝑗 if 𝐴 𝑖 > 𝐴[𝑗]
max{1 + 𝐿𝐼𝑆𝐴𝑙𝑡 𝑖 + 1, 𝑖 , 𝐿𝐼𝑆𝐴𝑙𝑡 𝑖 + 1, 𝑗 } o/w
Memoization structure? 𝑛 × 𝑛 array.
Filling order? Multiple possible
Outer loop: 𝑖 from 0 to 𝑛 − 1
Inner loop: 𝑗 from 𝑛 − 1 to 𝑖
Summing Up
The two recurrences have the same idea (add/don’t add, record the end
of the array closest to your next decision)
But thinking left-to-right vs. right-to-left

Both end up with an 𝑛 × 𝑛 memoization structure (both of which could


be cut down 𝑂(𝑛) memory if needed)
And 𝑂 𝑛2 running time.
But Wait! There’s more
Another recurrence at the end of these slides for more practice.

Instead of thinking “do I include this element or not?” for each element,
Ask “what’s the next element” or equivalently “what’s the longest
subsequence starting from me”
Get a different recurrence, but not a better running time.
Takeaways
When designing a dynamic program, we sometimes need to introduce
a second variable, that doesn’t appear in the program
Or a second recurrence that mixes with the first if other decisions affect
what’s optimal (beyond which problem you look at)

There might be more than one program available.


Extra Practice
Subset Sum
Given an array 𝐴[] of positive integers, and a number 𝑡 find whether
there is a subset of 𝐴[] that sums to exactly 𝑡.

0 1 2 3 4 5 6 7

5 6 3 6 5 2 8 10

If 𝑡 = 30, answer is “yes” (for example, 5 + 5 + 2 + 8 + 10)


If 𝑡 = 100, answer is “no” (not allowed to repeat elements beyond the
number of copies in the array, e.g. can’t say “10 copies of 10”)
Subset Sum
Write an English description of what you want to calculate

Write a recurrence

Give a sentence or two (in English) of why your recurrence should work.
Subset Sum
Write an English description of what you want to calculate
Let 𝑆𝑈𝐵𝑆𝑈𝑀(𝑖, 𝑡) be true if and only if a subset of 𝐴 0 , … , 𝐴[𝑖] can sum to 𝑡.

Write a recurrence
𝑇𝑟𝑢𝑒 if 𝑡 = 0
𝑆𝑈𝐵𝑆𝑈𝑀 𝑖, 𝑡 = ቐ 𝐹𝑎𝑙𝑠𝑒 if 𝑖 < 0 and 𝑡 ≠ 0
𝑆𝑈𝐵𝑆𝑈𝑀 𝑖 − 1, 𝑡 ||𝑆𝑈𝐵𝑆𝑈𝑀 𝑖 − 1, 𝑡 − 𝐴[𝑖] 𝑜/𝑤
Give a sentence or two (in English) of why your recurrence should work.
Element 𝑖 is either included or it isn’t – if 𝑖 appears in a valid subset, then we need
to have the remaining elements sum to 𝑡 − 𝐴[𝑖]. If 𝑖 doesn’t appear then the
remaining elements will get to 𝑡. We “or” together because either could be a valid
path to getting the right sum.
Subset Sum
What memorization structure will you use?
A 2D Boolean array SUBSUM(𝑖, 𝑗). Array will be 𝑛 × 𝑇
Write the pseudocode to fill up the structure iteratively.
SubSum(int[] A, int T)
Bool[][] SubSum = new Bool[n][T+1]
for(int j=0;j<T+1;j++){ SubSum[0][j]=False;}
SubSum[0][A[0]]=True;
for(int i=1; i<n;i++){
for(int j=0; j<T+1; j++){
if(SubSum[i-1][j]){
SubSum[i][j]=True;
SubSum[i][j+A[i]]=True;//need to catch Array index errors. Don’t do
//this in real code.
}
}
}
return SubSum[n][T-1];
Longest Increasing Subsequence, Round 3
Let’s ask “what’s the best choice for the next element” (instead of just “is
this the next element”
What’s the best choice?
It has to be greater than our current element, after that it’s the one that
can lead to the longest subsequence.

So, (since we’re starting with our current element), the question is
“what’s the longest increasing subsequence, starting at index 𝑖”
Longest Increasing Subsequence, Round 3
Let 𝐿𝐼𝑆𝑆𝑡𝑎𝑟𝑡(𝑖) be the length of the longest increasing subsequence
among indices 𝑖 … 𝑛, that starts at index 𝑖.

Call an index “valid” if 𝐴 𝑗 > 𝐴[𝑖] (it’s “valid” to add 𝑗 to a sequence


starting at 𝑖
𝐿𝐼𝑆𝑆𝑡𝑎𝑟𝑡(𝑖) = max{1, max 𝐿𝐼𝑆𝑆𝑡𝑎𝑟𝑡 𝑖 if 𝑖 ≤ 𝑛} }
𝑗:𝑗 𝑖𝑠 𝑣𝑎𝑙𝑖𝑑 𝑎𝑛𝑑 𝑗>𝑖
i.e. have a single entry (yourself) or prepend yourself to the longest
subsequence starting after you (that you can prepend yourself to)
Longest Increasing Subsequence, Round 3
Memoization? 1D array of size 𝑛
Iteration? Outer-loop: 𝑖 decreasing
Inner-loop: calculate 𝐿𝐼𝑆𝑆𝑡𝑎𝑟𝑡(𝑖) by iterating over previous calculations.
Checking 𝑛 values for each new calculation, not 𝑂(1)
Still 𝑂 𝑛2 time.

Be careful!
Final answer is not 𝐿𝐼𝑆𝑆𝑡𝑎𝑟𝑡(𝑖).
It’s the maximum entry among 𝐿𝐼𝑆𝑆𝑡𝑎𝑟𝑡() array
DP on Trees
DP on Trees
Trees are recursive structures

A tree is a root node, with zero or more children


Each of which are roots of trees

Since DP is “smart recursion” (recursion where we save values)


Recursive functions/calculations are really common.
DP on Trees
Find the minimum vertex cover in a tree.
Give every vertex a weight, find the minimum weight vertex cover
Vertex Cover
A set 𝑆 of vertices is a vertex cover if for every edge (𝑢, 𝑣):
𝑢 is in 𝑆, or 𝑣 is in 𝑆, (or both)

The weight of a vertex cover is just the sum of the weights of the
vertices in the set.
We want to find the minimum weight vertex cover.
Vertex Cover
Vertex Cover A set 𝑆 of vertices is a vertex cover if for every
edge (𝑢, 𝑣): 𝑢 is in 𝑆, or 𝑣 is in 𝑆, (or both)
Find the minimum vertex cover in
a tree. 1

Give every vertex a weight, find


the minimum weight vertex cover
10 8

5 3 20
Vertex Cover
Vertex Cover A set 𝑆 of vertices is a vertex cover if for every
edge (𝑢, 𝑣): 𝑢 is in 𝑆, or 𝑣 is in 𝑆, (or both)
Find the minimum vertex cover in
a tree. 1

Give every vertex a weight, find


the minimum weight vertex cover
10 8

A valid vertex cover! (just take everything)


Definitely not the minimum though.
5 3 20
Vertex Cover
Vertex Cover A set 𝑆 of vertices is a vertex cover if for every
edge (𝑢, 𝑣): 𝑢 is in 𝑆, or 𝑣 is in 𝑆, (or both)
Find the minimum vertex cover in
a tree. 1

Give every vertex a weight, find


the minimum weight vertex cover
10 8

A better vertex cover – weight 18

5 3 20
Vertex Cover
Vertex Cover A set 𝑆 of vertices is a vertex cover if for every
edge (𝑢, 𝑣): 𝑢 is in 𝑆, or 𝑣 is in 𝑆, (or both)
Find the minimum vertex cover in
a tree. 1

Give every vertex a weight, find


the minimum weight vertex cover
10 8

The minimum vertex cover: weight 17

5 3 20
Vertex Cover
Vertex Cover A set 𝑆 of vertices is a vertex cover if for every
edge (𝑢, 𝑣): 𝑢 is in 𝑆, or 𝑣 is in 𝑆, (or both)
Notice, the minimum weight
vertex cover might have both 1
endpoints of some edges
Even though only one of 1, 8 is
required on the edge between
8
them, they are both required for 10
other edges.

20
Also an indication that greedy 5 3
probably won’t work!
Vertex Cover – Recursively
Let’s try to write a recursive algorithm first.

What information do we need to decide if we include 𝑢?

If we don’t include 𝑢 then to be a valid vertex cover we need…

If we do include 𝑢 then to be a valid vertex cover we need…


Vertex Cover – Recursively
Let’s try to write a recursive algorithm first.

What information do we need to decide if we include 𝑢?

If we don’t include 𝑢 then to be a valid vertex cover we need…


to include all of 𝑢′ 𝑠 children, and vertex covers for each subtree
If we do include 𝑢 then to be a valid vertex cover we need…
just vertex covers in each subtree (whether children included or not)
Recurrence
Let 𝑂𝑃𝑇(𝑣) be the weight of a minimum weight vertex cover for the
subtree rooted at 𝑣.

Write a recurrence for 𝑂𝑃𝑇()


Then figure out how to calculate it
Recurrence
𝑂𝑃𝑇(𝑣) – the weight of the minimum weight vertex cover for the tree
rooted at 𝑣 (whether or not 𝑣 is included).
𝐼𝑁𝐶𝐿𝑈𝐷𝐸(𝑣) – the weight of the minimum weight vertex cover for the
tree rooted at 𝑣 where 𝑣 is included in the vertex cover.

𝑂𝑃𝑇 𝑣 = ቊmin{σ𝑢:𝑢 is a child of 𝑣 𝐼𝑁𝐶𝐿𝑈𝐷𝐸 𝑢 , 𝑤𝑒𝑖𝑔ℎ𝑡 𝑣 + σ𝑢:𝑢 is a child of 𝑣 𝑂𝑃𝑇(𝑢)} if 𝑣 is not a leaf
0 if 𝑣 is a leaf
𝐼𝑁𝐶𝐿𝑈𝐷𝐸 𝑣 = 𝑤𝑒𝑖𝑔ℎ𝑡 𝑣 + σ𝑢:𝑢 is a child of 𝑣 𝑂𝑃𝑇(𝑢)
Vertex Cover Dynamic Program
What memoization structure should we use?

What code should we write?

What’s the running time?


Vertex Cover Dynamic Program
What memoization structure should we use?
the tree itself!

What code should we write?

What’s the running time?


Vertex Cover

What order do we do the


calculation? 1

10 8

5 3 20
Vertex Cover Dynamic Program
What memoization structure should we use?
the tree itself!

What code should we write?


A post-order traversal (make recursive calls, then look up values in
children to do calculations)
What’s the running time?
Θ(𝑛)
DP Context
DP Design Notes
We haven’t done a single proof for DP…
We won’t ask you to do one.

DP proofs are almost always just “the code does the recurrence”
But that just moves the correctness question – why is the recurrence
correct?
And the proof of the recurrence being correct is almost always “I
included all the cases”
I’d rather you focus on checking it than trying to explain it.
DP history
So…why is it called “dynamic programming?”

“programming” is an old-timey meaning of the word.


It means “scheduling”
Like a conference has a “program” of who speaks where when.
Or a television executive decides on the nightly programming (what
show airs when).
DP history
So…dynamic?

The phrase “dynamic programming” was popularized by Richard


Bellman (we’ll see one of his algorithms on Monday)
He was a researcher, funded by the U.S. military….
But the Secretary of Defense [as Bellman tells it] hated research. And
hated math even more.

So Bellman needed a description of his research that everyone


DP history
Dynamic

Is actually an accurate adjective – what we think is the best option


(include/exclude) can change over time.
Even better
“It’s impossible to use the word ‘dynamic’ in a pejorative sense”
“It was something not even a Congressman could object to.”
Next week
Dynamic Programming on General graphs

Linear Programming

You might also like