Algorithms and Data Structures II

Document Sample
Algorithms and Data Structures II Powered By Docstoc
Programming & Data Structures
       Dynamic Programming

               Lecture 15        1
    Dynamic Programming
   An essential characteristic of the divide and conquer
    algorithms that we have seen is that they partition
    the problem into independent subproblems
   Solving the subproblems solves the original problem
   This paradigm is totally dependent on the
    subproblems being independent, but what if the
    subproblems are not independent?
   When the subproblems are not independent the
    situation is complicated, primarily because direct
    recursive implementation of even the simplest
    algorithms of this type can require unthinkable
    amounts of time.

                            Lecture 15                      2
    Fibonacci Numbers
   We have already talked about Fibonacci numbers
   These number are defined as,

       Fib(0) =     0
       Fib(1) =     1
       Fib(n) =     Fib(n-1) + Fib(n-2)

   Fibonacci numbers have many useful properties and
    appear often in nature
   We can implement these with a recursive function
    quite easily

                          Lecture 15                    3
     Recursive Fibonacci
            if x < 1 then return 0
            if x = 1 then return 1
            return Fib(x-1) + Fib(x-2)
   The problem is that this implementation runs in
    exponential time. It is spectacularly inefficient!
   For example, if the computer takes about a second to
    compute Fib(N), then we know it will take more than
    a minute to compute Fib(N+9) and more than an
    hour to compute Fib(N+18)

                                 Lecture 15                4
     Iterative Fibonacci
   If we implement the Function iteratively, by storing each value
    in an array we can compute it in linear time

         Fib(F, x)
             F[0] = 0
             F[1] = 1
             for i = 2 to x
               F[i] = F[i-1] + F[i-2]
   These numbers grow very large very quickly, so an array size of
    46 is sufficient to hold all the values
   In fact we can dispense with the array if we want and just keep
    track of the two previous numbers

                                    Lecture 15                        5
   The recursive implementation takes about a minute
    to calculate Fib(40), whereas the iterative solution is
    almost instantaneous.
   This technique gives us an immediate way to get
    numerical solutions for any recurrence relation
   A recurrence is a recursive function with integer
   Our analysis of the Fibonacci series suggests that we
    can evaluate any such function by computing all the
    values in order, starting at the smallest, using
    previously computed values at each step.
   We call this technique bottom-up dynamic
                             Lecture 15                       6
   It is an algorithm-design technique that has been
    used successfully for a wide range of problems
   The problem with the recursive implementation is
    that each recursive call ignores values calculated in
    earlier calls and so exponential duplication occurs
   The first nine Fibonacci numbers are
          0, 1, 1, 2, 3, 5, 8, 13, 21
   If we examine how, F(8) is calculated by the
    recursive implementation we can get a feel for what
    is happening
                 F(8) = 21

                            Lecture 15                      7
              Calculating F(8) Recursively

                                          13                                                              8

                         8                                   5                              5                          3
               5                      3                  3        2                     3        2                 2       1
          3         2             2                 2        1   1        0        2        1   1     0
                                          1                                                                    1       1 1 0
     2        1    1     0                      1       1 1 0    1 0           1       1 1 0    1 0
                              1       1 1 0                                                                   1 0
 1       1 1 0     1 0       1 0               1 0                            1 0
1 0

             Fib(5) is 3 which is calculated 5 times in this implementation
             If we could remember the value once calculated then we could remove
              these duplicate calculations

                                                         Lecture 15                                                        8
    Top-Down Approach
 This is what is done with top-down dynamic programming
 Get the algorithm to save each value it calculates, and at each
   call check if the value has already been calculated
            static knownF[MAX] = unknown
                if knownF[x] <> unkown then
                   return knownF[x]
                if x < 1 then t = 0
                if x = 1 then t = 1
                if x > 1 then
                   t = Fib(x-1) + Fib(x-2)
                knownF[x] = t
                return knownF[x]

                                    Lecture 15                      9
     Storing Intermediate Values
   Implemented in this top-down dynamic way the algorithm now
    runs in linear time
   By design, dynamic programming eliminates all recomputation
    in any recursive program

                                                   13            8

                                           8                 5

                                  5                     3

                          3                        2

                      2                    1
              1               1
          1       0

                                      Lecture 15                     10
    Knapsack Problem
   Consider a warehouse of capacity M and a load of N types of
    items of varying size and value, which we want to allocate into
    the warehouse.
   The problem is to find the combination of items which should be
    chosen to maximise the total value of all the items in the
   There are many applications which solutions to the knapsack
    problem are important.
   For example, a transport company might wish to know the best
    way to load a ship, truck or cargo plane
   In some of these cases other factors do complicate the problem,
    and in some cases the problems become infeasible

                                Lecture 15                            11
     Knapsack Problem
   In a recursive solution to the problem, each time we choose an
    item, we assume that we can (recursively) find an optimal way
    to pack the rest of the warehouse

        Knap(N, cap)
          max = 0
          for i = 1 to N
             space = cap - items[i].size
             if space >= 0 then
                  t = knap(space) + items[i].val
                  if t > max then
                            max = t
          return max

                                     Lecture 15                      12
     Knapsack Algorithm
 This algorithm works by calculating for each item (recursively)
    the maximum value that we could achieve by including that
    item and then taking the maximum of all those values
   However, this algorithm, like the simple recursive Fibonacci
    solution, runs in exponential time and so is not feasible
   Once more the reason is due to massive recomputation, and
    once more a dynamic programming approach can be useful
   To use top-down dynamic programming we need to remember
    intermediate solutions already calculated
   note: N = number of items

                                Lecture 15                          13
Dynamic Program Algorithm
static maxKnown[MAX] = unknown
Knap( M, N )
     max = 0
     if maxKnown[M] <> unknown then
            return maxKnown[M}
     max = 0
     for i = 1 to N
           space = M - items[i].size
           if space >= 0 then
                t = knap(space) + items[i].val
                if t > max then max = t, maxi = i endif
     maxKnown[M] = max
     itemKnown[M] = items[maxi]
     return max
                            Lecture 15                    14
 For the knapsack problem the running time is proportional to
   Bottom up dynamic programming could also be used for this
   In top-down dynamic programming we save known values; In
    bottom-up dynamic programming we precompute the values
   Dynamic programming is an effective algorithmic technique but
    can become ineffective if the number of possible function values
    is too high to save
   Also, if the values involved are floating point values, then we
    cannot save the values by indexing into an array
   This is a fundamental problem and no good solution is known to
    problems of this type

                                Lecture 15                             15
   The Divide and Conquer paradigm is dependent
    on the subproblems being independent
   If they are dependent then massive
    recomputation can occur
   Dynamic programming is a technique which
    remembers any intermediate calculations
   This can be done in a bottom-up or top-down
   In top-down dynamic programming we save
    known values; In bottom-up dynamic
    programming we precompute the values
                          Lecture 15               16

Shared By: