MCS 275 Spring 2024
Emily Dumas
Reminders and announcements:
This is fib(6). Notice how many calls (e.g. fib(3)) happen multiple times? Each results in more recursion.
It's even worse for fib(n) with larger n.
A technique to address this problem:
Let's memoize fib.
| n=35 | n=450 | |
|---|---|---|
| recursive (naive) | 1.9s | ≫ age of universe |
| recursive (memoized) | <0.001s | 0.003s |
| iterative | <0.001s | 0.001s |
Measured on my old office PC (2015, Intel i7-6700K) with Python 3.8.5
Another way to measure the cost of a recursive function is to count how many times the function is called.
Let's do this for recursive fib.
| $n$ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
|---|---|---|---|---|---|---|---|---|
| calls | 1 | 1 | 3 | 5 | 9 | 15 | 25 | |
| $F_n$ | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 |
fib is called to
compute fib(n). Then
$$T(0)=T(1)=1$$ and $$T(n) = T(n-1) + T(n-2) + 1.$$
Corollary: $T(n) = 2F_{n+1}-1$.
Proof of corollary: Both sequences $T(n)$ and $2F_{n+1}-1$ have the same first two terms, and obey the same recursion relation. Induction.
Corollary: $T(n) = 2F_{n+1}-1$.
Proof of corollary: Let $S(n) = 2F_{n+1}-1$. Then $S(0)=S(1)=1$, and $$\begin{split}S(n) &= 2F_{n+1}-1 = 2(F_{n} + F_{n-1}) - 1\\ &= (2 F_n - 1) + (2 F_{n-1}-1) + 1\\ & = S(n-1) + S(n-2) + 1\end{split}$$ Therefore $S$ and $T$ have the same first two terms, and follow the same recursive definition based on the two previous terms. By induction, the set of $n$ such that $T(n) = 2F_{n+1}-1$ is all of $\mathbb{N}$.
Corollary: Every time we increase $n$ by 1, the naive recursive fib
does $\approx61.8\%$ more work.
(The ratio $F_{n+1}/F_n$ approaches $\frac{1 + \sqrt{5}}{2} \approx 1.61803$.)

How do you solve a maze?

How do you solve a maze?
My guess at your approach:
A formal version of this recursion with backtracking. Start with
Add one more step to the path.
Make a recursive call to see what happens after that.
If the answer is "nothing good", consider a different next step.
Two stop conditions: Dead end or goal.
If goal: Great! Return the path as solution.
If dead end: Return None to tell whoever called us to try something else (to backtrack).
depth_first_maze_solution:
Input: a maze and a path under consideration (partial progress toward solution).
None, continue the loop.)None.
This method is also called a depth first search for a path through the maze.
Here, depth first means that we always add a new step to the path before considering any other changes (e.g. going back and modifying an earlier step).

Let's explore the Maze class from maze.py.
Same suggested references as Lecture 9.