Lab: Practice with Dynamic Programming and Optimal
Binary Search Trees
- Recall that the Fibonacci sequence is defined recursively as
follows:
- fib(0) = 1
- fib(1) = 1
- for n >= 2, fib(n) = fib(n-1) + fib(n02)
In practice, this sequence arises is a surprising number of
applications!
Program fibonacci.c defines two
procedures to compute the nth Fibonacci number.
- FibSeq1 uses the recurrence relation directly in its
computation.
- FibSeq2 follows the style of dynamic programming: an array
keeps track of each Fibonacci number when it is first computed.
- Compile and run the program to clarify what it does. (In the
interests of time, you may want to change the upper bound of the
loop in the main procedure from 45 to 41.)
- In fibSeq2, why do you think fibSeq2 has only an int as parameter,
rather than an int and an array as defined in fibSeq2Helper?
- Explain in a few sentences the role of the array arr.
- In fibSeq2Helper, why not declare and initialize the array in
one step?
int arr [n+1] = {0};
- Write a sentence or two to explain the test
if (fibArr[n] != 0)
- Explain why an assignment is included in the return statement
return fibArr[n] = 1;
Computing Combinations
A widely-used problem in computer science involves determining the
number of ways that k items can be chosen from a pool of n distinct
objects, ignoring the ordering of elements selected. In writing and
speech, this quantity is denoted several ways:
- "n choose k"
- C(n, k)
- combinations of n items taken k at a time
This "binomial coefficient" is discussed in CS 242 and on many Web
sites, such as Combinations
and Permutations by Maths is Fun.
Computationally, discussions of these combinations often specify a
computational formula involving factorials (where k factorial or k! = k*(k-1)*(k-2)*...*3*2*`)
C(n,k) = n! / [k! (n-k)!]
For example, the number of 5-card hands possible from a deck of 52
cards would be C(52, 5).
Although this formula works well on paper, a pragmatic problem is that
the computation of factorials produces large numbers very quickly:
-
The program factorial.c computes
successive factorials (1!, 2!, 3, ...) until integer overflow
occurs—the integer is too large to be stored in an integer
variable.
-
Compile and run this program and observe the output.
-
How large can an integer n be, so that n! can be computed as an
int?
-
Modify the program so the fact variable and associated
elements use a long integer rather than an int
How much does this increase in storage allow factorials to be
computed.
Since factorials are often too large for many simple computations,
alternative approaches are needed for computation. One approach uses
the recurrence relation:
- C(0, n) = 1 for all n
- C(n, n) = 1 for all n
- C(n, k) = C(n-1, k-1) + C(n-1, k) for all 1 <= k <= n-1
As well as being explained in CS 242, many online sources provide a
proof of this relation, including
Proposition:
Recursive Formula for Binomial Coefficients from the Book of
Proofs.
With this recurrence relation, alternative ways to compute C(n, k)
could follow either of two approaches:
-
Use the recurrence relation directly. (This function will
largely parallel function fibSeq1 in the Fibonacci program.)
-
Use a two-dimensional array to store values as they are
computed, so that each C(r, s) will only have to be computed
once. (This function will largely follow figSeq2 in the
Fibonacci program.)
These alternatives form the basis for the following programming task.
-
Write a program that reads values for n and k and computes C(n, k)
in the two ways described above.
-
Run your code with sufficient test cases, so you can give a
strong argument that the functions work properly. (And include
your argument in your solution of this problem.)
-
Once your functions work properly, add code to determine the
timing of each of these approaches. Write a brief
commentary to indicate the extent to which the table in the
second approach increases efficiency.
-
From your work in Step 2, you know values of n for which the
computation of n! fails, so the expression n! / [k! (n-k)!]
fails. Determine what, if any, larger values of C(n, k) can
be computed with your current program.
Optimal Binary Search Tree
-
Determine the cost and structure of an optimal binary search tree with the
following frequencies:
| Boxer
| Doberman
| Lab
| Spaniel
| Terrier
|
| 3
| 2
| 4
| 6
| 1
|