Dynamic Programming
Often there are more efficient ways to solve a problem
than recursion
It is not unusual for the recursive algorithm to solve
the same subproblem repeatedly
In this case, once a subproblem is solved, the
solution should be saved, often in a table
Dynamic programming is applicable when the subproblems
are not independent, that is, when subproblems share sub subproblems
Dynamic programming is typically applied to optimization
problems where there are many possible solutions; we want the best one.
Binomial coefficients
When you expand a
binomial to some power, the coefficients have some interesting properties.
Expand (x+y)2 (x+y)3 (x+y)4
The coefficients
make up Pascals triangle
Look at the properties of Pascals triangle
In addition, the coefficients can be found by the
formula
n C k = n!/ k!(n-k)!
where n is the power to which the binomial is expanded, and
k is the term kth term
This is the formula to find the number of combinations
of k elements from a set with a total
of n elements
Since the kth
term for n can be found in terms of n-1, we can use recursion to find n C k
Finding the factorial of a number is very expensive
Summary of binomial coefficients
They are the coefficients when expanding a binomial
like (x + y)
n is the power to
which the binomial is expanded
k is the number of
the term of the expansion
The are the values of Pascals triangle
They are the solution to the number of combinations
possible with n total elements, taken k at a time
Since binomial coefficients represent three different
things, we have a choice of how to program a way to find them
Recursive code to find n C k (the binomial coefficient)
Algorithm 3.1 from your text
public static int
binomialCoeff(int n, int k)
{ if k == 0 || k == n return 1
else return binomialCoeff(n-1, k-1) +
binomialCoeff(n-1, k);
}
Does this code
remind you of other code we have looked at in this class?
Two recursive calls that do not
reduce the size of the problem.
It is much like
our code to find the nth Fibonacci term
We make two
recursive calls, but we keep figuring the same stuff over and over.
So, there must be
a better way to do this, where we save in a table values that will be used
again
Steps for constructing a dynamic programming
algorithm
Establish a recursive property.
B[n][k] = B[n-1][k-1] + B[n-1][k] when 0<k<n
B[n][k] = 1 when k = 0 or k = n
Solve the problem from smallest to largest by computing the rows in B, starting with the first
row, saving the results
Example: find 5C3;
here n=5, k=3;
We want to find B[5][3]
B[row][col] =
B[row-1][col-1] + B[row-1][col] when
0<k<n
Find B[0][0] and put in the table in row 0 // not used
Find B[1][0], then B[1][1] in row 1
Find B[2][0], then B[2][1], then B[2][2] in row 2
Find B[3][0], B[3][1], B[3][2] , B[3][3] in row 3
Dynamic programming code to find n C k
(the binomial coefficient)
Algorithm 3.2
from your text
public static int
binCoeff2(int n, int k)
{ index row, col;
int [ ][ ] B = new int [0..n][0..k];
for(row=0; row<n;
row++)
for(col=0; col<minimum(row, k);
col++)
if (col==0 || col==row) B[row][col] = 1;
else B[row][col] = B[row-1][col-1] +
B[row-1][col];
return B[n][k];
}
Improving on the this code
How can you see that this code could be improved?
It is not really necessary to keep all the
values in a table
Once a row is
computed, the row before it is no longer needed
So we really
could get along with only a 1-D array, indexed from 0 to k
Anything else?
The table is
symmetric, and it is not really necessary to compute both sides of Pascals
triangle