TOWERS OF HANOI
: If n = 1, move disk 1 from pole 'A' to pole 'B'. else: 1.First, move n-1 disks from pole 'A' to pole 'C', using pole 'B' as a temporary. 2.Then move disk n from pole 'A' to pole 'B'. 3.Finally, move n-1 disks from pole 'C' to pole 'B', using pole 'A' as a temporary.
origin = 'A' origin = 'A' destination = 'B' temporary = 'C' Then the general strategy for moving n disks from origin to destination is as follows:
If n is 1, move disk 1 from origin to destination. Otherwise, 1.Move n - 1 disks (one at a time) from origin to temporary; 2. Move disk n from origin to destination; 3. Move n-1 disks (one at a time) from temporary to destination.
// Precondition: n > 0. Otherwise, IllegalArgumentException has // been thrown. // Postcondition: the steps needed to move n disks from pole orig // to pole dest have been written out. Pole temp is // used for temporary storage. The worstTime (n) is // O (2 n ). public void move (int n, char orig, char dest, char temp) { if (n <= 0) throw new IllegalArgumentException( ); if (n == 1) gui.println ("Move disk 1 from " + orig + " to " + dest); else { move (n ‑ 1, orig, temp, dest); gui.println ("Move disk " + n + " from " + orig + " to " + dest); move (n ‑ 1, temp, dest, orig) ; } // else } // method move
THE TOTAL NUMBER OF CALLS TO move IS: n … + 2 n-1 = 2 i i=0
n-1 2 i = 2 n - 1 i=0 SEE EXAMPLE 6 OF APPENDIX 1 FOR A PROOF BY MATHEMATICAL INDUCTION.
WE CONCLUDE THAT worstTime (n) is O (2 n ), AND 2 n IS THE SMALLEST UPPER BOUND OF worstTime (n).
BACKTRACKING
Backtracking Backtracking is the strategy of trying to reach a goal by a sequence of chosen positions, with re-tracing in reverse order of position that cannot lead to the goal.
P14 (GOAL) P13 P4 P12 P7 P3 P11 P6 P5 P2 P10 P9 P8 P1 P0
WHEN A POSITION IS VISITED, IT IS MARKED AS (POTENTIALLY) BEING ON A PATH TO THE GOAL. IF WE DISCOVER OTHERWISE, THE MARKING MUST BE UNDONE, SO THAT POSITION WILL NEVER AGAIN BE VISITED.
GENERAL-PURPOSE Backtrack CLASS USER SUPPLIES: AN Application OBJECT A Position OBJECT AN Iterator OBJECT
import java.util.*; public class BackTrack { Application app; // Postcondition: this BackTrack has been initialized from app. public BackTrack (Application app) { this.app = app; } // constructor
// Postcondition: a solution going through pos has been attempted. public boolean tryToSolve (Position pos) { boolean success = false; Iterator itr = app.iterator (pos); while (!success && itr.hasNext()) { pos = (Position)itr.next(); if (app.valid (pos)) { app.record (pos); if (app.done (pos)) success = true; else { success = tryToSolve (pos); if (!success) app.undo (pos); } // not done } // a valid position } // while return success; } // method tryToSolve } // class BackTrack
POSSIBLE MOVES FROM pos IN tryToSolve: SUCCESS, IF ONE OF THOSE MOVES IS A GOAL POSITION; HOPEFUL, IF ONE OF THOSE MOVES IS VALID BUT NOT A GOAL POSITION. RECURSIVE CALL! FAILURE, IF NONE OF THOSE MOVES IS ON A PATH TO GOAL;
IMPORTANT: WHEN A RETURN IS MADE, THE PRE-CALL VALUE OF pos IS RESTORED. SO THE PREVIOUSLY VISITED POSITIONS ARE AVAILABLE, TO BE PRINTED AS PART OF THE PATH TO THE GOAL, TO BE UNDONE,...
import java.util.*; public interface Application { // Postcondition: true has been returned if pos could be on a path to a // goal position. // Otherwise, false has been returned. public boolean valid (Position pos); // Postcondition: the position specified by pos has been marked as //being on a path to a goal position. public void record (Position pos); // Postcondition: true has been returned if pos is a goal position. //Otherwise, false has been returned. public boolean done (Position pos);
// Postcondition: the position specified by pos has been marked //as not being on a path to a goal position. public void undo (Position pos); // Postcondition: a string representation of this Application has //been returned. public String toString(); // Postcondition: an iterator over the positions directly accessible //from pos has been returned. public Iterator iterator (Position pos); } // interface Application
MAZE SEARCHING: 1 = CORRIDOR; 0 = WALL start finish ITERATOR CHOICES: NORTH, EAST, SOUTH, WEST
SOLUTION: 9 = PATH; 2 = DEAD END
public class Maze implements Application { protected final byte WALL = 0; protected final byte CORRIDOR = 1; protected final byte PATH = 9; protected final byte TRIED = 2; protected Position finish; protected byte[ ][ ] grid;
public boolean valid (Position pos) { if (pos.row() >= 0 && pos.row() < grid.length && pos.column() >= 0 && pos.column() < grid [0].length && grid [pos.row()][pos.column()] == CORRIDOR) return true; return false; } // method valid public void record (Position pos) { grid [pos.row()][pos.column()] = PATH; } // method record public boolean done (Position pos) { return pos.row() == finish.row() && pos.column() == finish.column(); } // method done
private class MazeIterator implements Iterator { int row, column, count = 0; public MazeIterator (Position pos) { row = pos.row(); column = pos.column(); } // constructor public boolean hasNext() { return count < 4; } // method hasNext
// Precondition: 0 <= count <= 3. // Postcondition: the choice for the next Position has // been returned. public Object next() { Position nextPosition = new Position(); switch (count++) { case 0: nextPosition = new Position (row-1, column); // NORTH break; case 1: nextPosition = new Position (row, column+1); // EAST break; case 2: nextPosition = new Position (row+1, column); // SOUTH break; case 3: nextPosition = new Position (row, column-1); // WEST } // switch; return nextPosition; } // method next
GROUP EXERCISE: SHOW FINAL GRID start finish ITERATOR CHOICES: NORTH, SOUTH, EAST, WEST