Introduction to Algorithm Design: Dynamic Programming - Study Guide | CS 1510, Study notes of Computer Science

Material Type: Notes; Professor: Pruhs; Class: ALGORITHM DESIGN; Subject: Computer Science; University: University of Pittsburgh; Term: Unknown 1989;

Typology: Study notes

Pre 2010

Uploaded on 09/02/2009

koofers-user-8pb-1
koofers-user-8pb-1 🇺🇸

7 documents

1 / 10

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
1 Dynamic Programming: Take 1
We examine problems that can be solved by dynamic programming, perhaps
the single most useful algorithmic design technique. Dynamic programming
can be explained many ways. Rather than explain what a dynamic program-
ming algorithm is, we explain how one might develop one:
1. Find a recursive algorithm for the problem. It often helps to first find a
recursive algorithm to count the number of feasible solutions.
2. Spot redundancy in the calculation
3. Eliminate the redundancy. This can often be best accomplished by per-
forming the calculations bottom up, instead of top down.
2 Fibonacci Numbers and Binomial Coeffi-
cients
See section 1.2.2 and section 3.1 from the text.
3 Longest Common Subsequence Problem
The input to this problem is two sequences A=a1,...,amand B=b1,...,bn.
The problem is to find the longest sequence that is a subsequence of both
Aand B. For example, if A=ccdedcdec and B=cdedcdec, then cddec is
subsequence of length 5 of both sequences. Let T(i, j ) be the length of the
longest common subsequence of a1,...,aiand b1,...,bj. Then one can see
that if ai=bjthen T(i, j ) = T(i1, j 1) + 1. Otherwise, one can see that
T(i, j) = max(T(i, j 1), T (i1, j)).
Note that there are only nm possible subproblems since there are only m
choices for iand nchoices for j. Hence, by treating the T(i, j )’s as array
entries (instead of recursive calls) and updating the table in the appropriate
way we can get the following O(n2) time algorithm.
1
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Introduction to Algorithm Design: Dynamic Programming - Study Guide | CS 1510 and more Study notes Computer Science in PDF only on Docsity!

1 Dynamic Programming: Take 1

We examine problems that can be solved by dynamic programming, perhaps the single most useful algorithmic design technique. Dynamic programming can be explained many ways. Rather than explain what a dynamic program- ming algorithm is, we explain how one might develop one:

  1. Find a recursive algorithm for the problem. It often helps to first find a recursive algorithm to count the number of feasible solutions.
  2. Spot redundancy in the calculation
  3. Eliminate the redundancy. This can often be best accomplished by per- forming the calculations bottom up, instead of top down.

2 Fibonacci Numbers and Binomial Coeffi-

cients

See section 1.2.2 and section 3.1 from the text.

3 Longest Common Subsequence Problem

The input to this problem is two sequences A = a 1 ,... , am and B = b 1 ,... , bn. The problem is to find the longest sequence that is a subsequence of both A and B. For example, if A = ccdedcdec and B = cdedcdec, then cddec is subsequence of length 5 of both sequences. Let T (i, j) be the length of the longest common subsequence of a 1 ,... , ai and b 1 ,... , bj. Then one can see that if ai = bj then T (i, j) = T (i − 1 , j − 1) + 1. Otherwise, one can see that T (i, j) = max(T (i, j − 1), T (i − 1 , j)).

Note that there are only nm possible subproblems since there are only m choices for i and n choices for j. Hence, by treating the T (i, j)’s as array entries (instead of recursive calls) and updating the table in the appropriate way we can get the following O(n^2 ) time algorithm.

For i=0 to m do T(i,0)=

For j=0 to n do T(0,j)=

For i=1 to m do For j= 1 to n do if a(i) = b(j) then T(i,j)=T(i-1,j-1) + 1 else T(i,j)= MAX( T(i, j-1), T(i-1, j))

4 Computing Number of Binary Search Trees

and Optimal Binary Search Trees

Section 3.5 from the text.

5 Chained Matrix Multiplication

Section 3.4 from the text.

6 Maximum Weight Independent Set in a Tree

The input to this problem is a tree T with weights on the vertices. The goal is to find the independent set in T with maximum aggregate weight. An independent set is a collection of mutually nonadjacent vertices.

Root the tree at an arbitrary node r, and process the tree in postorder. We generalize the induction hypothesis. Consider an arbitrary node v with branches to k descendants w 1 , w 2 ,... , wk. We can create an independent set for the subtree rooted at v in essentially two ways depending on whether or not we include v in the independent set. If we decide not to include v, Consider an arbitrary root v with branches to k descendants w 1 , w 2 ,... , wk. We can create an independent set for the subtree rooted at v in essentially

Let us try to develop a recursive algorithm for this problem. Let LIS(k) be the longest increasing subsequence of the first k integers in X. Consider the following first stab at an induction hypothesis:

Induction Hypothesis 1: We know how to compute LIS(k).

Assume that we have computed LIS(k − 1), and we now want to compute LIS(k). The following sequence 1, 4 , 2 , 3 shows that we can’t just know any longest sequence. Before we consider 3, we need to know the LIS 1, 2, not the LIS 1, 4. The obvious solution is to remember the LIS that ends in the smallest number. Hence we change the definition of LIS as follows: Let LIS(k) be the the longest increasing subsequence of the first k integers in X that ends in the smallest number.

Induction Hypothesis 2: We know how to compute LIS(k).

The following sequence 12, 13 , 14 , 1 , 2 , 4 shows that knowing the LIS that ends in the smallest number is not sufficient information. Notice that in this example the length of the LIS doesn’t change, but a new one is formed with a smaller last number. The most obvious way to fix this problem is to remember the best (the one that ends in the smallest number) sequence of length one less than the LIS. Let LIS2(k) be the the increasing subsequence of the first k integers in X that has length one less than the length of LIS(k) and that ends in the smallest number.

Induction Hypothesis 3: We know how to compute LIS(k), and LIS2(k).

The following sequence 12, 13 , 14 , 15 , 1 , 2 , 3 shows that there is not sufficient inductive information to compute LIS2(k). We need to know the sequence of the first k−1 integers in X of length two shorter than LIS(k−1) that ends in the smallest number. One can see that eventually we have to inductively know the sequence of each length that ends in the smallest number.

Hence, we define LIS(k, s) as the the smallest last number of any subsequence of length s from among the first k numbers of X. This then leads us to the following algorithm.

For k= 0 to n do for s= 1 to n do LIS(k, s) = plus infinity

For k= 0 to n do LIS(k, 0) = minus infinity

For k= 1 to n do for s= 1 to n do if ( LIS(k-1, s-1) < x(k) < LIS(k-1, s) then LIS(k,s)=x(k) else LIS(k,s)=LIS(k-1,s)

This is an example of where when trying to compute something recursively/inductive it is sometimes easier to compute more information than you need. This is sometimes called strengthening the inductive hypothesis. This is not para- doxical because the strengthening of the inductive hypothesis also gives you more information to work with when the recursion returns from the smaller subproblem. The most common mistake made here is to use the additional information returned from the recursion to solve the original problem, not the more generalized problem.

One point that I want you to draw from this example is that its not always easy to determine how one should strengthen the inductive hypothesis.

8 Dynamic Programming: Take 2

In this section we discuss another method for developing dynamic program- ming algorithms that avoids having to develop a recursive algorithm, which is almost always the most difficult part in the previously outlined method. This method is particularly applicable when the feasible solutions are subsets or subsequences. The steps to developing a dynamic programming algorithm using this method are as follows:

  1. Determine how to generate all possible feasible solutions. Once again it might be easier to first determine how to count the number of feasible solutions. Enumeration usually follows easily from counting.

10 Knapsack Example

The knapsack problem can be defined as follows:

INPUT: A collection of objects O 1 ,... , On with positive integer weights w 1 ,... , wn, and positive integer values v 1 ,... , vn. A positive integer L.

OUTPUT: The highest valued subset of the objects with weight at most L.

We can generate the subsets inductively using a binary tree as in the subset sum problem. The two pruning rules are

  1. Eliminate the subtree rooted at any subset with sum greater than L.
  2. If there are two subsets S and T at the same depth, with the same total weight, then eliminate the one of least value.

Note that these two pruning rules mean that there are at most L + 1 nodes left unpruned at any level. Let V alue[k, S] be highest value one can obtain from a subset of the first k numbers with aggregate weight S. We compute V alue[k, S] as follows:

Value[0,0]= For S=1 to L do Sum[0, S]= minus infinity

For k=1 to n do For S = 0 to L do Value[k, S] = Max( Value[k-1, S], Value[k-1, S - w(k)] + v(k) )

11 Longest Increasing Subsequence Problem:

Take 2

We now apply this method to the longest increasing subsequence problem. We can generate feasible solutions (subsequences) as in the subset sum prob- lem. One obvious the pruning rule is:

  1. If you have two subsequences S and T at the same depth that have the same length, prune the one that ends in the larger number.

This pruning rule will give you at most n unpruned nodes at any level. If you turn this into an iterative code, you will get the same code as we got before. Another possible pruning rule would be:

  1. If two sequences S and T at the same depth have the same last number, prune the shorter sequence.

This pruning rule will also give you at most n unpruned nodes at any depth, and an (n^2 ) time algorithm.

Note how much easier it was to develop an algorithm for the LIS problem this way, as opposed to trying recursion and generalizing the induction hypothesis.

12 The Single Source Shortest Path Problem

The input to this problem is a directed positive edge weighted graph with a designated vertex s. The problem is to find the shortest simple path from s to each other vertex. For more information see section 4.2 of the text.

Here feasible solutions are simple paths that start from the source vertex s. The nodes in level k of the tree represent all paths from s of k or less hops. Note that by simplicity we we need only consider the tree to depth n, the number of vertices.

The pruning rule is that we need only remember the shortest path to a particular vertex. We thus get the following code. Here D[k, i] is the shortest path from s to i of k or less hops.

The running time of this code is O(V E 2 V^ ), where V is the number of vertices and E is the number of edges.

14 The Traveling Salesman Problem

See section 3.6 from the text.

The input to this problem is a directed edge weighted graph with a designated vertex s. The edge weights may be positive or negative. The problem is to find the shortest simple path from s that visits all of the vertices.

Here feasible solutions are simple paths that start from the source vertex s. The nodes in level k of the tree represent all paths from s of exactly k. Note that by simplicity we we need only consider the tree to depth n, the number of vertices.

The pruning rule is that if two paths end at the same vertex and contain the same vertices then we may prune the shorter one.

We thus get the following code. Here D[k, S, i] is the shortest path from s to i of k or less hops that visits exactly the vertices in S.

For k= 1 to n do For i= 1 to n do For S= 1 to 2^n do for each edge e = (i, j) do if j is not in S then D[k, S+ j, j]=min( D[k, S+j, j], D[k, S, i] + the length of e )

The running time of this code is O(V E 2 V^ ), where V is the number of vertices and E is the number of edges.