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 Pascal’s triangle

–    Look at the properties of Pascal’s 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 Pascal’s 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 Pascal’s triangle