CSCE 235

Light Bulb 8

March 31, 2004

 

1.   What is the use of Recursion?  There are many ways in which Recursion can be useful.   Suppose that newborn rabbits start producing offspring by the end of their second month of life an that after this point, they produce a pair a month (one male, one female).  Assuming just one pair of rabbits initially, how many pairs of rabbits, Fibonacci asked, will be alive after one year.  This becomes the Fibonacci sequence.  After one month, there is still only one pair of rabbits in existence, but after a further month, this pair is joined by its offspring; thus, after two months, there are two pairs of rabbits.  At the end of any month, the number of pairs of rabbits is the number alive at the end of the previous month plus the number of pairs alive two months ago, since each pair alive two months ago produced one pair of offspring.  This can be expressed as a recursion.

 

2.   There is another concern.  Recursive calculation requires storage addresses for the intermediate values that have been called for but not yet computed.  It may be possible, though, to keep the number of storage slots fairly small.  For example, the recursive calculation of FACT(6) goes like this:

 

            FACT(6) = 6FACT(5) = 30FACT(4) = 120FACT(3) = ….

 

Only one address is needed for the intermediate [unknown] value FACT(k) for k < 6.  Similarly, for a Fibonacci sequence:

 

            FIB(6)  = FIB(5) + FIB(4) = (FIB(4) + FIB(3)) + FIB(4)

                        = 2FIB(4) + FIB(3)

                        = 3FIB(3) + 2FIB(2)

                        = 5FIB(2) + 3FIB(1)

                        = 8FIB(1) + 5FIB(0)

 

only requires two intermediate addresses.

 

3.   As discussed in the class, if a recursion is linear and second order, we can express it in terms of two previous items in the recursion sequence.  Then, we can actually express the recursion in terms of the item and remove the recursion factor explicitly from the sequence.  This is a wonderful and powerful application.  In this manner, we are able to reduce computational and storage requirements for our algorithm designs.  Please refer to Handout 18 on Sequences and Recursions.

 

4.   A famous puzzle is the so-called The Towers of Hanoi.  It consists of three pegs and a number of discs of differing diameters, each with a hole in the center.  The discs initially sit on one of the pegs in order of decreasing diameter (smallest at top, largest at bottom, as in Figure 1), thus forming a triangular tower.  The object is to move the tower to one of the other pegs by transferring the discs to any peg one at a time in such a way that no disc is ever placed upon a smaller one.

Figure 1  The Towers of Hanoi

 

      How do we solve this problem?

 

First, let us look at an easy case where the number of discs is n = 2.  If we label the pegs A, B, and C, we use an asterisk (*) to denote an empty peg, and we number the discs in order of increasing size (so disc 1 is the smallest), then we have a solution:

 

 

A

B

C

Initial Position

1,2

*

*

Move 1

2

1

*

Move 2

*

1

2

Move 3

*

*

1,2

 

Now, if n = 3, then we have:

 

 

A

B

C

Initial Position

1,2,3

*

*

Move 1

2,3

*

1

Move 2

3

2

1

Move 3

3

1,2

*

Move 4

*

1,2

3

Move 5

1

2

3

Move 6

1

*

2,3

Move 7

*

*

1,2,3

 

      In the first case, we need 3 moves; and in the second case, we need 7 moves.

 

Now, suppose that  is the number of moves needed to solve the puzzle with n discs.  Can we represent  as a recursion relation?  We now know that when n = 0,  = 0; when n = 1,  = 1; when n = 2,  = 3; when n = 3,  = 7.  To find a recursion, we want to express  in terms of  and/or , and so on.  A first guess is: .  By inspection, we realize that it works for the first few cases.  We check to see whether it works for n = 4:

 

 

A

B

C

Initial Position

1,2,3,4

*

*

Move 1

2,3,4

1

*

Move 2

3,4

1

2

Move 3

3,4

*

1,2

Move 4

4

3

1,2

Move 5

1,4

3

2

Move 6

1,4

2,3

*

Move 7

4

1,2,3

*

Move 8

*

1,2,3

4

Move 9

*

2,3

1,4

Move 10

2

3

1,4

Move 11

1,2

3

4

Move 12

1,2

*

3,4

Move 13

2

1

3,4

Move 14

*

1

2,3,4

Move 15

*

*

1,2,3,4

 

So, we need 15 moves above.  And according to our guesswork, , which confirms what we observe. 

 

If it takes one second to move one disc, how much time does it take to solve a puzzle with four discs?  According to our formula:   seconds.  What about when there are 8 discs—i.e., n = 8?  We can solve the problem by:

 

.

 

What about when there are 16 discs? 32 discs? 64 discs?

 

This is getting more and more tedious to compute.  Now we can apply what we have learned!

 

If we include the initial position as one move, then we have , or  where a = 2 and b = 0.   Solving the characteristic equation, we have  or .  Thus, .  Since we have only one distinct solution, we know that we can express  as (see Handout 9):

 

 

Since we are now including the initial position as one move, we know that  = 2 when n = 1, and  = 4 when n = 2.  So, we have:

 

 

Solving the above equations for the constants, we have  = 1, and  = 0.  Thus, we have !

 

Now, we can go back and take out the initial position:

 

.

 

Now, we see that it works for the first few cases, from n = 0 to n = 4.  Now, we are ready to answer the questions:  how many seconds does it take to solve a puzzle with 16 discs, 32 discs, or 64 discs?  Now, we can simply use . 

 

Isn’t this elegant?  Now, we have reduced a previously recursive function to a formula that no longer depends on previous sequence values.  As a result, we are able to answer the questions faster and more easily.

 

Based on (Ross and Wright 1988) and (Goodaire and Parmenter 2002).