Dynamic Programming - Data Structures - Lab, Exercises of Data Structures and Algorithms

Some concept of Data Structures are Data Structures, Dynamic Programming, First-In-First-Out, Implementation, Python Code. Main points of this lecture are: Dynamic Programming, Dividing, Original Problem, Small Problem, Solving, Combine the Solution, Recursively Defined, Simple, Binomial Coefficient Formula, Hands

Typology: Exercises

2012/2013

Uploaded on 04/30/2013

naji
naji 🇮🇳

4.3

(6)

87 documents

1 / 2

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Objective: To gain experience with a simple, recursive, divide-and-conquer implementation and how to develop
faster solutions using an iterative dynamic programming implementation
To start the lab: Download and unzip the file at:
Part A: We’ve seen several recursive “divide-and-conquer” algorithms: binary search and fibonacci. The
general idea of divide-and-conquer algorithms is:
dividing the original problem it into small problem(s) (e.g., fib(n-1) and fib(n-2))
solving the smaller problem(s)
combine the solution(s) to smaller problem(s) to solve the original problem (e.g., return fib(n-1) + fib(n-2) )
Mathematics has several simple recursively defined functions. For example, the factorial function can be
recursively defined as:
(1) n! = n * (n - 1)! for n 1, and
0! = 1
Implement a recursive factorial(n) function using this recursive definition and test it with several small
examples (e.g., 3! = 3*2! = 3*2*1! = 3*2*1*0! = 3*2*1*1 = 6, and 5! = 5*4*3*2*1*1 = 120).
In Discrete Structures (CS 1800) you used (or will use) the binomial coefficient formula:
(2)
C(n,k) = n!
k!(nk)!
to calculate the number of combinations of “n choose k,” i.e., the number of ways to choose k objects from n
objects. For example, when calculating the number of unique 5-card hands from a standard 52-card deck (e.g.,
C(52, 5)) we need to calculate 52! / 5! 47! = 2,598,960.
Implement the function C(n, k) using formula (2) above and your recursive factorial function.
Completed your factorial and binomial coefficient functions, raise your hand and demonstrate your code.
Part B: One problem with using formula (2) in most languages is that n! grows very fast and overflows the
integer representation before you can do the division to bring the value back to a value that can be represented.
(NOTE: Python does not suffer from this problem, but lets pretend that it does.)
For example, when calculating C(52, 5) we need to calculate 52! / 5! 47!. However, the value of
52! = 80,658,175,170,943,878,571,660,636,856,403,766,975,289,505,440,883,277,824,000,000,000,000
is much, much bigger than can fit into a 64-bit integer representation. Fortunately, another way to view C(52, 5)
is recursively by splitting the problem into two smaller problems by focusing on:
the hands containing a specific card, say the ace of clubs, and
the hands that do not contain the ace of clubs.
For those hands that do contain the ace of clubs, we need to choose 4 more cards from the remaining 51 cards,
i.e., C(51, 4). For those hands that do not contain the ace of clubs, we need to choose 5 cards from the remaining
51 cards, i.e., C(51, 5). Therefore, C(52, 5) = C(51, 4) + C(51, 5).
In general,
(3) for , and
C(n,k) = C(n1, k1) + C(n1, k)1[k[(n1)
1 for k = 0 or k = n
C(n,k) =
Implement the recursive “divide-and-conquer” binomial coefficient function using equation (3). Call your
function DC(n,k) for “divide-and-conquer”. Notice the difference in run-time between calculating the binomial
coefficient using C(24, 12) vs. DC(24, 12), C(26, 13) vs. DC(26, 13), and C(28, 14) vs. DC(28, 14).
Completed your binomial coefficient function, DC, raise your hand and demonstrate your code.
Part C: Much of the slowness of your “divide-and-conquer” binomial coefficient function, DC(n, k), is due to
redundant calculations performed due to the recursive calls. For example, the recursive calls associated with
DC(5, 3) = 10 would be:
Data Structures (CS 1520) Lab 6 Name:_________________
Lab
6
-
1
Docsity.com
pf2

Partial preview of the text

Download Dynamic Programming - Data Structures - Lab and more Exercises Data Structures and Algorithms in PDF only on Docsity!

Objective: To gain experience with a simple, recursive, divide-and-conquer implementation and how to develop faster solutions using an iterative dynamic programming implementation

To start the lab: Download and unzip the file at:

Part A: We’ve seen several recursive “divide-and-conquer” algorithms: binary search and fibonacci. The general idea of divide-and-conquer algorithms is:

  • dividing the original problem it into small problem(s) (e.g., fib(n-1) and fib(n-2))
  • solving the smaller problem(s)
  • combine the solution(s) to smaller problem(s) to solve the original problem (e.g., return fib(n-1) + fib(n-2) )

Mathematics has several simple recursively defined functions. For example, the factorial function can be recursively defined as: (1) n! = n * ( n - 1)! for n ≥ 1, and 0! = 1 Implement a recursive factorial(n) function using this recursive definition and test it with several small examples (e.g., 3! = 32! = 321! = 3210! = 3211 = 6, and 5! = 543211 = 120).

In Discrete Structures (CS 1800) you used (or will use) the binomial coefficient formula:

(2) C ( n , k ) =

n! k !( nk )!

to calculate the number of combinations of “n choose k,” i.e., the number of ways to choose k objects from n objects. For example, when calculating the number of unique 5-card hands from a standard 52-card deck (e.g., C(52, 5)) we need to calculate 52! / 5! 47! = 2,598,960.

Implement the function C(n, k) using formula (2) above and your recursive factorial function.

Completed your factorial and binomial coefficient functions, raise your hand and demonstrate your code.

Part B: One problem with using formula (2) in most languages is that n! grows very fast and overflows the integer representation before you can do the division to bring the value back to a value that can be represented. (NOTE: Python does not suffer from this problem, but lets pretend that it does.) For example, when calculating C(52, 5) we need to calculate 52! / 5! 47!. However, the value of 52! = 80,658,175,170,943,878,571,660,636,856,403,766,975,289,505,440,883,277,824,000,000,000, is much, much bigger than can fit into a 64-bit integer representation. Fortunately, another way to view C(52, 5) is recursively by splitting the problem into two smaller problems by focusing on:  the hands containing a specific card, say the ace of clubs, and  the hands that do not contain the ace of clubs. For those hands that do contain the ace of clubs, we need to choose 4 more cards from the remaining 51 cards, i.e., C (51, 4). For those hands that do not contain the ace of clubs, we need to choose 5 cards from the remaining 51 cards, i.e., C (51, 5). Therefore, C (52, 5) = C (51, 4) + C (51, 5).

In general, (3) (^) C ( n , k ) = C ( n − 1, k − 1 ) + C ( n − 1, k ) for (^1) [ k [ ( n − 1 ), and C ( n , k ) = 1 for k = 0 or k = n Implement the recursive “divide-and-conquer” binomial coefficient function using equation (3). Call your function DC(n,k) for “divide-and-conquer”. Notice the difference in run-time between calculating the binomial coefficient using C(24, 12) vs. DC(24, 12), C(26, 13) vs. DC(26, 13), and C(28, 14) vs. DC(28, 14).

Completed your binomial coefficient function, DC, raise your hand and demonstrate your code.

Part C: Much of the slowness of your “divide-and-conquer” binomial coefficient function, DC(n, k), is due to redundant calculations performed due to the recursive calls. For example, the recursive calls associated with DC(5, 3) = 10 would be:

Data Structures (CS 1520) Lab 6 Name:_________________

Docsity.com^ Lab^6 -^1

DC(4, 2)

DC(5, 3)

DC(4, 3)

DC(3, 2) DC(3, 2) DC(3, 3)

DC(2, 2) DC(2, 2)

DC(1,0)DC(1,1) DC(1,0) DC(1,1) DC(1,0)DC(1,1)

DC(2, 0) DC(2, 1) DC(2, 1) DC(2, 1)

DC(3, 1)

Pascal’s triangle (named for the 17th-century French mathematician Blaise Pascal, and for whom the programming language Pascal was also named) is a “dynamic programming” approach to calculating binomial coefficients.

Row # 0 1 2 3 4

. 5 .^.

Recall that dynamic programming solutions eliminate the redundancy of recursive divide-and-conquer algorithms by calculating the solutions to smaller problems first, storing their answers, and looking up their answers if later needed instead of recalculating it. Abstractly, Pascal’s triangle relates to the binomial coefficient as in:

C(0,0)

Row # 0 1 2 3 4 (^5). .

..

n

C(1,0) C(1,1)

C(2,0) C(2,1) C(2,2)

C(3,0) C(3,1) C(3,2) C(3,3)

C(4,0) C(4,1) C(4,2) C(4,3) C(4,4)

C(5,0) C(5,1) C(5,2) C(5,3) C(5,4) C(5,5)

C(n,0) C(n,1) C(n,2)... C(n,k) C(n, n-1) C(n,n)

C(n-1,k-1) C(n-1,k) n-

For Part C, your job is to implement the “dynamic programming” binomial coefficient function using Python lists and loops (no recursion needed). Call your function DP(n,k) for “dynamic programming”. Hints for Part C:  Review the dynamic programming fibonacci example from Lecture 9. File lab6/fibonacci.py contains the recursive divide-and-conquer, and two dynamic programming versions of fibonacci. The first dynamic programming version, fib_DP, stores the answers to all of the smaller problems. The second dynamic programming version, fib_DP2, reduces the amount of memory used by only storing the answers for the previous two smaller problems.  Your function DP(n,k)should use the idea of fib_DP2 to avoid storing all the answers to the smaller problems. Notice that the calculation of the next row in the picture above only needs the previous row and none of the older rows. Notice the difference in run-time between calculating the binomial coefficient using DC(24, 12) vs. DP(24, 12), DC(26, 13) vs. DP(26, 13), and DC(28, 14) vs. DP(28, 14).

Completed your binomial coefficient function, DP, raise your hand and demonstrate your code.

Data Structures (CS 1520) Lab 6 Name:_________________

Docsity.com^ Lab^6 -^2