daily puzzle - · pdf filethe josephus problem
TRANSCRIPT
![Page 1: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/1.jpg)
Lecture 24The mysteries of recursion
Daily Puzzle
![Page 2: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/2.jpg)
Recursion
• The process of recursion may have had its birth in literature. For example, the poem “Sacred Emily”, by Gertrude Stein (1913):
A rose is a rose is a rose
is a rose.
The Droste Effect
• A Dutch term for a specific kind of recursive picture in which an image depicts a smaller version of itself in a place where a similar picture would realistically be expected to appear.
![Page 3: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/3.jpg)
![Page 4: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/4.jpg)
Recursion in Nature
• Structures in nature that contain substructures with the same form as the whole exhibit something known as “self-similarity”.
![Page 5: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/5.jpg)
Visual recursion
• Recursion is used to generate fractals
“a rough or fragmented geometric shape that can be split into parts, each of which is (at least approximately) a reduced-size copy of the whole”.
Hilbert curves
• A continuous fractal space-filling curve first described by the German mathematician David Hilbert (1862-1943) in 1891.
![Page 6: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/6.jpg)
Hilbert curves
Koch snowflake
• One of the earliest fractals, derived from the Koch curve of 1904 by Swedish mathematician Helge von Koch.
![Page 7: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/7.jpg)
Koch snowflake
Cesaro curve, based on Koch infrastructure
Recursion
• Recursion is a programming technique that naturally implements the divide-and-conquer programming methodology.
![Page 8: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/8.jpg)
Barron, in his monograph entitled “Recursive Techniques in
Programming” (1968) said:
“if computers had existed in the Middle Ages, programmers would have been burned at the stake by
other programmers for heresy”
...“it is certain that one of the main heresies would have
been a belief (or disbelief) in recursion”
How is it performed?
• The notion of recursion is linked to the idea of a stack.
• Edsger Dijkstra first described this in 1960.
![Page 9: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/9.jpg)
A STACK WORKS LIKE A PEZ DISPENSER
LIFO - Last-In, First-Out
Items are added by being pushed onto the stack, and
removed by being popped off the stack
A STACK FOR A RUNNING C
PROGRAM USING A RECURSIVE
FUNCTION X.
The stack is used to store a stack frame for each function
that has been called.
static variables
main()
function X called from main()
function X_1 called from X
function X_2 called from X_1
current stack frame
Note that stacks have finite storage.
![Page 10: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/10.jpg)
How does it work?
if (this is a simple case) solve itelse redefine the problem using recursionend if
! Calculating xn
! e.g. x5 = x * x * x * x * x
! and is broken down as:
! x * (x * x * x * x)! x * (x * (x * x * x))! x * (x * (x * (x * x)))! x * (x * (x * (x * (x))))
![Page 11: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/11.jpg)
Is recursion useful?
• Depends on the problem being solved.
• Is it a recursive problem?
• If not, does a recursive solution offer simplicity, or efficiency?
Many types of recursion
• Linear recursion.
• Binary recursion.
• Nested recursion.
• Mutual recursion.
![Page 12: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/12.jpg)
Is recursion good?
• Yes, but not always.
• Some recursive solutions are ubiquitous... - but horrible.
• Don’t use recursion just for the sake of using recursion.
Fibonacci
• Classic, yet “naïve” binary recursive form of deriving Fibonacci numbers.
• Used in nearly every textbook containing recursion.
• It works but at what cost?
![Page 13: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/13.jpg)
Version of Fibonacci algorithm in C:
int fib(int n){ if (n <= 2) return 1; else return fib(n-1) + fib(n-2);}
fib(5)
fib(4) fib(3)
fib(3) fib(2) fib(2) fib(1)
1fib(2) fib(1)
1
1 1
1
+
+
+
+
![Page 14: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/14.jpg)
Fibonacci
• The algorithm grows in exponential time.
• Calculating fib(200) requires approximately 2140 operations.
• Biggest problem is time spent recalculating already calculated numbers.
Fibonacci
Put into perspective:
Fujitsu K computer @ 10.51 petaflops10.51×1015 floating-point ops / sec
2140 = 1.3×1026 seconds≈ 4.2×1016 millennia
![Page 15: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/15.jpg)
Fibonacci
Calculating fib(40):fib(35) calculated 8 times, and
fib(1 or 2) calculated 102,334,155 times.
Total = 204,668,309 function calls
A better way - linear recursion?
int fib(int a, int b, int n){ if (n <= 2) return b; else if (n > 2) return fib(b,a+b,n-1);}
called using f = fib(1,1,n)
for n=40 39 function calls total
0 seconds
![Page 16: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/16.jpg)
A mutually recursive way
for n=40 120 seconds
int fib_babies(int i){ if (i == 1) return 1; else return fib_adults(i-1);}
int fib_adults(int i){ if (i == 1) return 0; else return fib_adults(i-1) + fib_babies(i-1);}
Rubio and Pajak
called using f = fib_adults(n) + fib_babies(n);
A quick recursive way
for n=40 63 recursive calls,
0 seconds
Dijkstra / Shortt
long long fib_DijkstraR(int n){! long long i,j,tempi,tempj;! if (n == 0)! ! return 0;! if (n == 1)! ! return 1;
! if (n%2 == 0){ //even! ! i = (n-1) / 2;! ! j = n / 2;! ! tempi = fib_DijkstraR(i);! ! tempj = fib_DijkstraR(j);! ! return (2 * tempi + tempj) * tempj;! }! else { //odd! ! i = n / 2;! ! j = (n+1) / 2;! ! tempi = fib_DijkstraR(i);! ! tempj = fib_DijkstraR(j);! ! return tempi * tempi + tempj * tempj;! }}
![Page 17: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/17.jpg)
A quick recursive way
CAREFUL!!
Dijkstra / Shortt
tempi = fib_DijkstraR(i);tempj = fib_DijkstraR(j);return (2 * tempi + tempj) * tempj;
DO THIS
return (2 * fib_DijkstraR(i) + fib_DijkstraR(j)) * fib_DijkstraR(j);
NOT THIS!
Towers of Hanoi
• A classic CS example of recursion.
• Simple to implement...harder to conceptualize.
![Page 18: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/18.jpg)
The puzzle was invented by the French mathematician
François Édouard Anatole Lucas (1842-1891) in 1883.
TofH recursive algorithm in C
void hanoiR(int N, int from, int to, int using){ if (N > 0) { hanoiR(N-1, from, using, to); printf("move %d -> %d\n", from, to); hanoiR(N-1, using, to, from); }}
called using hanoiR(3, 1, 3, 2);
![Page 19: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/19.jpg)
hanoiR(3, 1, 3, 2)!! hanoiR(2, 1, 2, 3) ! ! hanoiR(1, 1, 3, 2)! ! ! hanoiR(0, 1, 2, 3) -> recursion terminates! ! move 1 -> 3! ! ! hanoiR(0, 2, 3, 1) -> recursion terminates! ! move 1 -> 2! ! hanoiR(1, 3, 2, 1)! ! ! hanoiR(0, 3, 1, 2) -> recursion terminates! ! ! move 3 -> 2! ! ! hanoiR(0, 1, 2, 3) -> recursion terminates! move 1 -> 3! hanoiR(2, 2, 3, 1)! ! hanoiR(1, 2, 1, 3)! ! ! hanoiR(0, 2, 3, 1) -> recursion terminates! ! ! move 2 -> 1! ! ! hanoiR(0, 3, 1, 2) -> recursion terminates! ! move 2 -> 3! ! hanoiR(1, 1, 3, 2)! ! ! hanoiR(0, 1, 2, 3) -> recursion terminates! ! ! move 1 -> 3! ! ! hanoiR(0, 2, 3, 1) -> recursion terminates
Iterative approaches?
• Using stacks.
• Using 2D arrays.
• A *lot* more code, and algorithm complexity.
![Page 20: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/20.jpg)
#include <stdio.h>
int disk[3][3] = {{1,0,0},{1,0,0},{1,0,0}};
void print_tower(){ printf("%d %d %d\n", disk[0][0], disk[0][1], disk[0][2]); printf("%d %d %d\n", disk[1][0], disk[1][1], disk[1][2]); printf("%d %d %d\n", disk[2][0], disk[2][1], disk[2][2]); printf("\n");}
// Function to determine if all the disks have been movedint is_moved(void){ if (disk[0][2] == 1 && disk[1][2] == 1 && disk[2][2] == 1) return 1; else { return 0; }}
// Function to determine the index, moving counter-clockwiseint ccw(int index){ if (index == 0) return 2; else return index - 1;}
// Function to determine the tower position of the smallest// diskint find_smallest_disk(void){ int disc; if (disk[0][0] == 1) disc = 0; else if (disk[0][1] == 1) disc = 1; else if (disk[0][2] == 1) disc = 2; return disc;}
// Function to return the tower position of the next disk to move.
void find_next_disk(int *disc, int *tower){
int i,j,k,found=1,df,su,disc_pos;
i = 1; while (i <= 2) {
// Check each disc row below the top to find a disc to move j = 0; df = 0; while (j <= 2) { if (disk[i][j] == 1) { df = 1; disc_pos = j; break; } else j = j + 1; } // Check the disc to make sure it can be moved
su = 0; for (k=i-1; k>=0; k=k-1) su = su + disk[k][disc_pos];
if (su == 0) { *disc = i; *tower = disc_pos; break; } else i = i + 1; }}
// Function to move the disk
void move_disk(int disc, int from, int to){ disk[disc][from] = 0; disk[disc][to] = 1;}
int main (void){ int smallest, d, disc, tower;
smallest = find_smallest_disk(); d = ccw(smallest); move_disk(0,smallest,d);
while (!is_moved()) { print_tower();
find_next_disk(&disc, &tower); if (disc == 1){ d = ccw(tower); d = ccw(d); } else if (disc == 2) d = ccw(tower);//printf("%d %d %d\n", disc, tower, d);
move_disk(disc,tower,d); print_tower();
smallest = find_smallest_disk(); d = ccw(smallest); move_disk(0,smallest,d); } print_tower();
return 0;}
Many other algorithms
• Mergesort, Quicksort.
• Greatest common divisor.
• Factorial.
• Palindrome, 8-Queens.
• Maze searching,
• Solving Sudoku.
![Page 21: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/21.jpg)
Ackermann’s Function
• Originated in 1928.
• Used extensively for studies in computational efficiency.
• Highly recursive.
• But - few real applications.
Ackermann’s Function
![Page 22: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/22.jpg)
Ackermann’s Function
A(1,2)= A(0, A(1,1))= A(0, A(0, A(1,0)))= A(0, A(0, 2))= A(0, 3)= 4
Ackermann’s Function
! int ackermann(int m, int n)! {! ! if (m == 0) ! return(n+1);! ! else if (n == 0) ! return(ackermann(m-1,1));! ! else ! return(ackermann(m-1,ackermann(m,n-1)));! } !
nested recursion
![Page 23: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/23.jpg)
Ackermann’s Function
• Can be used to illustrate recursive depth.
• Ackermann(2,2) produces the following recursive structure...
A(2,2)A(1,A(2,1))A(1,A(1,A(2,0)))A(1,A(1,A(1,1)))A(1,A(1,A(0,A(1,0))))A(1,A(1,A(0,A(0,1))))A(1,A(1,A(0,2)))A(1,A(1,3))A(1,A(0,A(1,2)))A(1,A(0,A(0,A(1,1))))A(1,A(0,A(0,A(0,A(1,0)))))A(1,A(0,A(0,A(0,A(0,1)))))A(1,A(0,A(0,A(0,2))))A(1,A(0,A(0,3)))A(1,A(0,4))A(1,5)A(0,A(1,4))A(0,A(0,A(1,3)))A(0,A(0,A(0,A(1,2))))A(0,A(0,A(0,A(0,A(1,1)))))A(0,A(0,A(0,A(0,A(0,A(1,0))))))A(0,A(0,A(0,A(0,A(0,A(0,1))))))A(0,A(0,A(0,A(0,A(0,2)))))A(0,A(0,A(0,A(0,3))))A(0,A(0,A(0,4)))A(0,A(0,5))A(0,6)7
![Page 24: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/24.jpg)
Ackermann’s Function
• Cannot be computed with only definite iteration (a completely defined for loop for example).
• Can be solved using a complex stack.
Ackermann’s Function
Ackermann(4,1)=6553331.85 s
Nonrecursive algorithm using a stack 91.17 s
![Page 25: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/25.jpg)
Pitfalls of recursion
• No guarantee of convergence.
• Excessive space requirements.
• Excessive re-computation.
• Laborious debugging.
Recursion and problem solving
• Look at various approaches to solving a problem.
• Is recursion the best solution?
![Page 26: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/26.jpg)
The Josephus Problem
• Originates from Roman historian Flavius Josephus (37-100).
• Basically a “reduction using a step of size k” problem.
The Josephus Problem
• A group of n people are standing in a circle, numbered consecutively clockwise from 1 to n.
• Starting with the first person, every kth person is removed, proceeding clockwise.
• What is the position of the remaining survivor?
![Page 27: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/27.jpg)
The Josephus Problem
If n = 6, and k=2, then people are removed in the following order:
2, 4, 6, 3, 1
the last person remaining is no. 5.
The Josephus Problem
➊
➋
➌
➍
➎
➏ ×
×
×
×
×
![Page 28: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/28.jpg)
➊
➋
➌
➍
➎
➏
➊
➌
➍
➎
➏
➊
➌➎
➏
➊
➌➎
➊
➎ ➎
×
×
×
×
×
The Josephus Problem
• What’s the best algorithm to use?
![Page 29: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/29.jpg)
The Josephus Problem
• The structure is circular, so a circular array, or linked list is the easiest.
• The problem can also be solved recursively... it’s just trickier.
The Josephus Problem
!int josephus(int n)!{!! if (n == 1)!!! return 1;!! if (n % 2 == 0)!!! return 2 * josephus(n / 2) - 1;!! else!!! return 2 * josephus(n / 2) + 1;!}
works for removing every 2nd person.
![Page 30: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/30.jpg)
Car Parking
Car Parking
void park(double lower, double upper){ double p; p = drand_RANGE(lower,upper); num = num + 1; printf("Car parked at position %.1f\n", p); if ((p-0.5)-(lower-0.5) >= 1.0) park(lower,p-1.0); if ((upper+0.5)-(p+0.5) >= 1.0) park(p+1.0,upper);}
park(0.5,9.5);
initial c
all
![Page 31: Daily Puzzle - · PDF fileThe Josephus Problem](https://reader034.vdocuments.mx/reader034/viewer/2022042605/5a9688817f8b9aba4a8ccafb/html5/thumbnails/31.jpg)
Car Parking
double drand_RANGE(double low, double high){ int randomNum; double drand, span;! randomNum = (double)rand(); drand = randomNum / (double) RAND_MAX; span = high - low; return low + span * drand;}
derive random numbers between low and high