mathematical games guru mg mg.org SciAm col list
mg 1959 Jan col about mazes and how they can be traversed
in mg book 2: Origami Eleusis and the Soma Cube
what algorithm did you use to solve it?
current cell <-- origin while current cell != destination current cell <-- random neighbour of current cell print current cell
this implementation is recursive
pro: easy to describe, leave some implementation details to language implementers
con: harder to learn, lose control to language implementers (e.g. stack overflow)
correct? (does it always do what it is supposed to?)
yes: every reachable location will, with positive probability, be reached
proof: consider a path from start to goal with distance t
assume each cell has at most k neighbours
what is prob that we reach the goal after exactly t iterations?
at least 1 / (k^t)
efficient? (w.r.t. time? w.r.t. space?)
no: if at least one nbr of start cell is not goal, then for any positive integer n, probability that there are at least n iterations is positive
proof: start-notgoal-start-notgoal-start-notgoal …
prob. we are on this path after n iterations at least 1/(k^n)
can it be improved?
hint: Theseus's thread, Hansel+Gretel's breadcrumbs:
keep track of visited cells
current cell <-- origin mark current cell while current cell != destination current cell <-- unmarked random neighbour of current cell mark current cell print current cell
correct? (does it always do what it is supposed to?)
no: why?
efficient?
yes: for a maze with n cells, at most n-1 iterations (why?)
X X X X X X a - b - c - d X . . . . X | | X . X . X X e f X . . X . X | X . . . . X g - h i X X X X X X | | | j - k - l - m nodes or points: a b c ... m edges or lines: ab ae bc cd cf eg gh gj hk im jk kl lm
our version
from a given start node, see what nodes we can reach by following edges
maintain list L of nodes seen but not yet explored
do not add a node to a list if we have already seen it
breadth first search:
L is queue, FIFO list
so remove node appended earliest
iterative depth-first search:
L is stack, LIFO list
so remove node appended most recently
depth-first search
recursive (recurse as soon as unseen nbr found)
differs slightly from iterative-dfs
for all nodes v: v.seen <- False L = [start], start.seen = True while not empty(L): v <- L.remove() for each neighbour w of v: if w.seen==False: L.append(w), w.seen = True
use the above adjacency graph, start from node j initialize L = [ j ] while loop execution begins remove j from L L now [ ] nbrs of j are g,k append g to L, g.seen <- T L now [ g ] append k to L, k.seen <- T L now [ g, k ] while loop continues (bfs, so L is queue, so remove g) remove g from L L now [ k ] nbrs of g are e,h,j append e to L, e.seen <- T L now [ k, e ] append h to L, h.seen <- T L now [ k, e, h ] j already seen while loop continues: remove k from L v <- k L now [ e, h ] nbrs of k are j,h,l j already seen h already seen append l to L, l.seen <- T L now [ e, h, l ] while loop continues: ...
complete the above bfs trace
hint: order in which edges are examined is jg jk ge gh gj kh kj kl …
so order of removal from L is j g k e h l a m b i c d f
perform an iterative dfs trace
hint: only difference is that list is stack
for all nodes v: v.seen <- False def dfs(v): v.seen <- True for each neighbour w of v: if w.seen==False: dfs(w) dfs(start)
use above graph, start from j dfs(j) nbrs g,k . dfs(g) nbrs e,h,j . . dfs(e) nbrs a,g . . . dfs(a) nbrs b,e . . . . dfs(b) nbrs a,c . . . . . a already seen . . . . . dfs(c) nbrs b,d,f . . . . . . b already seen . . . . . . dfs(d) nbrs c . . . . . . . c already seen . . . . . . dfs(f) nbrs c . . . . . . . c already seen . . . . e already seen . . . g already seen . . dfs(h) nbrs g,k . . . g already seen . . . dfs(k) nbrs g,h,l . . . . g already seen . . . . h already seen . . . . dfs(l) nbrs k,m . . . . . k already seen . . . . . dfs(m) nbrs l,i . . . . . . l already seen . . . . . . dfs(i) nbrs m . . . . . . . m already seen . . j already seen . k already seen
- assume nbrs are stored in alphabetic order - iterative bfs: order of removal from list? j g k e h l a m b i c d f - iterative dfs: order of removal from list? j k l m i h g e a b c f d - recursive dfs: order of dfs() calls? j g e a b c d f h k l m i - iterative dfs with nbrs added to list in reverse order: j g e a b c d f k h l m i notice that this differs from recursive dfs
list cells examined in FIFO manner (queue)?
list cells examined in FILO manner (stack)?