Recursive Backtracking Based on slides by Marty Stepp & Ethan Apter

Slides:



Advertisements
Similar presentations
BackTracking Algorithms
Advertisements

Announcements Assignment #4 is due tonight. Last lab program is going to be assigned this Wednesday. ◦ A backtracking problem.
CompSci 100e Program Design and Analysis II March 3, 2011 Prof. Rodger CompSci 100e, Spring
Building Java Programs
Backtracking COP Backtracking  Backtracking is a technique used to solve problems with a large search space, by systematically trying and eliminating.
Building Java Programs
Building Java Programs Chapter 12 Recursion Copyright (c) Pearson All rights reserved.
CSE 143 Lecture 17 More Recursive Backtracking reading: "Appendix R" on course web site slides created by Marty Stepp and Hélène Martin
HISTORY The problem was originally proposed in 1848 by the chess player Max Bezzel, and over the years, many mathematicians, including Gauss have worked.
CSE 143 Lecture 17 More Recursive Backtracking reading: "Appendix R" on course web site slides created by Marty Stepp and Hélène Martin
Announcements This Wednesday, Class and Labs are cancelled! The last lab is due this Wednesday … how many people are planning on doing it? Finally posted.
Data Structures Using C++ 2E1 Recursion and Backtracking: DFS Depth first search (a way to traverse a tree or graph) Backtracking can be regarded as a.
CSE 143 Lecture 18 Recursive Backtracking reading: 12.5 or "Appendix R" on course web site slides adapted from Marty Stepp and Hélène Martin
Building Java Programs Appendix R Recursive backtracking.
CPS Backtracking, Search, Heuristics l Many problems require an approach similar to solving a maze  Certain mazes can be solved using the “right-hand”
The "8 Queens" problem Consider the problem of trying to place 8 queens on a chess board such that no queen can attack another queen. What are the "choices"?
CompSci 100e 6.1 Plan for the week l More recursion examples l Backtracking  Exhaustive incremental search  When we a potential solution is invalid,
CSE 143 Lecture 18 More Recursive Backtracking slides created by Marty Stepp
CompSci Backtracking, Search, Heuristics l Many problems require an approach similar to solving a maze ä Certain mazes can be solved using the.
CSE 143 Lecture 13 Recursive Backtracking slides created by Ethan Apter
CPS Backtracking, Search, Heuristics l Many problems require an approach similar to solving a maze ä Certain mazes can be solved using the “right-hand”
Recursion Copyright (c) Pearson All rights reserved.
Recursion. 2 recursion: The definition of an operation in terms of itself. –Solving a problem using recursion depends on solving smaller occurrences of.
CPS 100, Spring Search, Backtracking,Heuristics l How do you find a needle in a haystack?  How does a computer play chess?  Why would you write.
CSE 143 Lecture 17 Recursive Backtracking slides created by Marty Stepp ideas and examples taken from Stanford University.
CSE 143 read: 12.5 Lecture 18: recursive backtracking.
1 Tirgul 11: Recursion & Backtracking. 2 Elements of a recursive solution (Reminder) A base case that is so simple we need no computation to solve it.
CSG3F3/ Desain dan Analisis Algoritma
Backtracking, Search, Heuristics
BackTracking CS255.
Intro to Computer Science II
CSCI 104 Backtracking Search
Data Structures and Algorithms
Huffman Coding Based on slides by Ethan Apter & Marty Stepp
read: 12.5 Lecture 17: recursive backtracking
The "8 Queens" problem Consider the problem of trying to place 8 queens on a chess board such that no queen can attack another queen. What are the "choices"?
CSE 143 Lecture 19 More Recursive Backtracking
Using a Stack Chapter 6 introduces the stack data type.
Building Java Programs
Recursion Copyright (c) Pearson All rights reserved.
Problem Solving: Brute Force Approaches
CSCI 162 – Introduction to Programming II Prof. William Killian
Writing Methods AP Computer Science A.
Analysis and design of algorithm
Using a Stack Chapter 6 introduces the stack data type.
Exercise: fourAB Write a method fourAB that prints out all strings of length 4 composed only of a’s and b’s Example Output aaaa baaa aaab baab aaba baba.
Exercise: Dice roll sum
CSE 143 Lecture 17 Recursive Backtracking
Road Map - Quarter CS Concepts Data Structures Java Language
adapted from Recursive Backtracking by Mike Scott, UT Austin
CSE 143 Lecture 17 Recursive Backtracking
Using a Stack Chapter 6 introduces the stack data type.
CSE 143 Lecture 15 Recursive Backtracking
Using a Stack Chapter 6 introduces the stack data type.
Exercise: Dice roll sum Write a method diceSum similar to diceRoll, but it also accepts a desired sum and prints only arrangements that add up to.
Exercise: Dice roll sum
Road Map - Quarter CS Concepts Data Structures Java Language
CSE 143 Lecture 18 More Recursive Backtracking
Recursive backtracking
Exercise: Dice rolls Write a method diceRoll that accepts an integer parameter representing a number of 6-sided dice to roll, and output all possible arrangements.
CSE 143 Lecture 18 More Recursive Backtracking
The N-Queens Problem Search The N-Queens Problem Most slides from Milos Hauskrecht.
Exercise: Dice roll sum
Recursive backtracking
The "8 Queens" problem Consider the problem of trying to place 8 queens on a chess board such that no queen can attack another queen. What are the "choices"?
slides created by Ethan Apter and Marty Stepp
CSE 143 Lecture 12 Recursive Backtracking
Backtracking, Search, Heuristics
Announcements Assignment #4 is due tonight. Last lab program is going to be assigned this Wednesday. ◦ A backtracking problem.
Backtracking, Search, Heuristics
Presentation transcript:

Recursive Backtracking Based on slides by Marty Stepp & Ethan Apter CSE 143 Lecture 18 Recursive Backtracking Based on slides by Marty Stepp & Ethan Apter

Exercise Write a method permute that accepts a string as a parameter and outputs all possible rearrangements of the letters in that string. The arrangements may be output in any order. Example: permute("MARTY") outputs the following sequence of lines: MARTY MARYT MATRY MATYR MAYRT MAYTR MRATY MRAYT MRTAY MRTYA MRYAT MRYTA MTARY MTAYR MTRAY MTRYA MTYAR MTYRA MYART MYATR MYRAT MYRTA MYTAR MYTRA AMRTY AMRYT AMTRY AMTYR AMYRT AMYTR ARMTY ARMYT ARTMY ARTYM ARYMT ARYTM ATMRY ATMYR ATRMY ATRYM ATYMR ATYRM AYMRT AYMTR AYRMT AYRTM AYTMR AYTRM RMATY RMAYT RMTAY RMTYA RMYAT RMYTA RAMTY RAMYT RATMY RATYM RAYMT RAYTM RTMAY RTMYA RTAMY RTAYM RTYMA RTYAM RYMAT RYMTA RYAMT RYATM RYTMA RYTAM TMARY TMAYR TMRAY TMRYA TMYAR TMYRA TAMRY TAMYR TARMY TARYM TAYMR TAYRM TRMAY TRMYA TRAMY TRAYM TRYMA TRYAM TYMAR TYMRA TYAMR TYARM TYRMA TYRAM YMART YMATR YMRAT YMRTA YMTAR YMTRA YAMRT YAMTR YARMT YARTM YATMR YATRM YRMAT YRMTA YRAMT YRATM YRTMA YRTAM YTMAR YTMRA YTAMR YTARM YTRMA YTRAM interesting variation: Output only the *unique* rearrangements. For example, permute("GOOGLE") has two Os, but swapping them in order produces the same string, which shouldn't appear twice in the output.

Examining the problem Think of each permutation as a set of choices or decisions: Which character do I want to place first? Which character do I want to place second? ... solution space: set of all possible sets of decisions to explore We want to generate all possible sequences of decisions. for (each possible first letter): for (each possible second letter): for (each possible third letter): print! This is called a depth-first search

Decision Trees chosen available M A R T Y M A R T Y A M R T Y M A ... M A R T Y M R A T Y M T A R Y M Y A R T ... ... ... M A R T Y M A T R Y M A Y R T M Y A R T ... ... M A R T Y M A R Y T M A Y R T M A Y T R M A R T Y M A R Y T M A Y R T M A Y T R

Backtracking backtracking: A general algorithm for finding solution(s) to a computational problem by trying partial solutions and then abandoning them ("backtracking") if they are not suitable. a "brute force" algorithmic technique (tries all paths; not clever) often (but not always) implemented recursively Applications: producing all permutations of a set of values parsing languages games: anagrams, crosswords, word jumbles, 8 queens combinatorics and logic programming

Backtracking algorithms A general pseudo-code algorithm for backtracking problems: explore(choices): if there are no more choices to make: stop. else: Make a single choice C from the set of choices. Remove C from the set of choices. explore the remaining choices (given that you’ve made choice C). Un-make choice C. Backtrack!

Backtracking strategies When solving a backtracking problem, ask these questions: What are the "choices" in this problem? What is the "base case"? (How do I know when I'm out of choices?) How do I "make" a choice? Do I need to create additional variables to remember my choices? Do I need to modify the values of existing variables? How do I explore the rest of the choices? Do I need to remove the made choice from the list of choices? Once I'm done exploring the rest, what should I do? How do I "un-make" a choice?

Permutations revisited Write a method permute that accepts a string as a parameter and outputs all possible rearrangements of the letters in that string. The arrangements may be output in any order. Example: permute("MARTY") outputs the following sequence of lines: MARTY MARYT MATRY MATYR MAYRT MAYTR MRATY MRAYT MRTAY MRTYA MRYAT MRYTA MTARY MTAYR MTRAY MTRYA MTYAR MTYRA MYART MYATR MYRAT MYRTA MYTAR MYTRA AMRTY AMRYT AMTRY AMTYR AMYRT AMYTR ARMTY ARMYT ARTMY ARTYM ARYMT ARYTM ATMRY ATMYR ATRMY ATRYM ATYMR ATYRM AYMRT AYMTR AYRMT AYRTM AYTMR AYTRM RMATY RMAYT RMTAY RMTYA RMYAT RMYTA RAMTY RAMYT RATMY RATYM RAYMT RAYTM RTMAY RTMYA RTAMY RTAYM RTYMA RTYAM RYMAT RYMTA RYAMT RYATM RYTMA RYTAM TMARY TMAYR TMRAY TMRYA TMYAR TMYRA TAMRY TAMYR TARMY TARYM TAYMR TAYRM TRMAY TRMYA TRAMY TRAYM TRYMA TRYAM TYMAR TYMRA TYAMR TYARM TYRMA TYRAM YMART YMATR YMRAT YMRTA YMTAR YMTRA YAMRT YAMTR YARMT YARTM YATMR YATRM YRMAT YRMTA YRAMT YRATM YRTMA YRTAM YTMAR YTMRA YTAMR YTARM YTRMA YTRAM interesting variation: Output only the *unique* rearrangements. For example, permute("GOOGLE") has two Os, but swapping them in order produces the same string, which shouldn't appear twice in the output.

Permutations Exercise // Outputs all permutations of the given string. public static void permute(String s) { permute(s, ""); } private static void permute(String avail, String chosen) { if ( ) { // base case: no choices left to be made } else { // recursive case: choose each possible next letter

Permutations Exercise // Outputs all permutations of the given string. public static void permute(String s) { permute(s, ""); } private static void permute(String avail, String chosen) { if (avail.length() == 0) { // base case: no choices left to be made System.out.println(chosen); } else { // recursive case: choose each possible next letter for (int i = 0; i < avail.length(); i++) {

Permutations Exercise // Outputs all permutations of the given string. public static void permute(String s) { permute(s, ""); } private static void permute(String avail, String chosen) { if (avail.length() == 0) { // base case: no choices left to be made System.out.println(chosen); } else { // recursive case: choose each possible next letter for (int i = 0; i < avail.length(); i++) { String ch = avail.substring(i, i + 1); // choose ith String rest = avail.substring(0, i) + // remove ith avail.substring(i + 1); // explore

Exercise solution // Outputs all permutations of the given string. public static void permute(String s) { permute(s, ""); } private static void permute(String avail, String chosen) { if (avail.length() == 0) { // base case: no choices left to be made System.out.println(chosen); } else { // recursive case: choose each possible next letter for (int i = 0; i < avail.length(); i++) { String ch = avail.substring(i, i + 1); // choose ith String rest = avail.substring(0, i) + // remove ith avail.substring(i + 1); permute(rest, chosen + ch); // explore

8 Queens 8 Queens is a classic backtracking problem 8 Queens: place 8 queens on an 8x8 chessboard so that no queen threatens another queens can move in a straight line horizontally, vertically, or diagonally any number of spaces possible moves threatened! safe!

Solve 8 Queens with Recursive Backtracking Consider the problem of trying to place 8 queens on a chess board such that no queen can attack another queen. What are the "choices"? How do we "make" or "un-make" a choice? How do we know when to stop? Q

Naive algorithm for (each square on the board): Place a queen there. Try to place the rest of the queens. Un-place the queen. How large is the solution space for this algorithm? 1 2 3 4 5 6 7 8 Q ... 64 * 63 * 62 * ...

8 Queens One possible approach: on an 8x8 chessboard, there are 64 locations each of these locations is a potential location to place the first queen (this is a choice!) after we place the first queen, there are 63 remaining locations to place the second queen clearly, some of these won’t work, because the second queen will threaten the first queen. after we place the second queen, there are 62 remaining locations to place the third queen and so on So, there are 178,462,987,637,760 possibilities! 178,462,987,637,760 = 64*63*62*61*60*59*58*57

8 Queens That’s a lot of choices! Remember that we’re using a brute-force technique, so we have to explore all possible choices now you can really see why brute-force techniques are slow! However, if we can refine our approach to make fewer choices, we can go faster we want to be clever about our choices and make as few choices as possible Fortunately we can do a lot better

Better algorithm idea Observation: In a working solution, exactly 1 queen must appear in each row and in each column. Redefine a "choice" to be valid placement of a queen in a particular column. How large is the solution space now? 1 2 3 4 5 6 7 8 Q ... 8 * 8 * 8 * ...

8 Queens Key observation: all valid solutions to 8 Queens will have exactly 1 queen in each row and exactly 1 queen in each column (otherwise the queens must threaten each other) There are exactly 8 queens, 8 rows, and 8 columns So rather than exploring 1-queen-per-board-location, we can explore 1-queen-per-row or 1-queen-per-column it doesn’t matter which We’ll explore 1-queen-per-column

for column #1, in which row should the queen be placed? 8 Queens When exploring column-by-column, we have to decide which row to place the queen for a particular column There are 8 columns and 8 rows so we’ve reduced our possible choices to 88 = 16,777,216 So our first decision looks something like this: for column #1, in which row should the queen be placed? 1 2 3 4 5 6 7 8

8 Queens If we choose to place the queen in row #5, our decision tree will look like this: Keep in mind that our second choice (column #2) is affected by our first choice (column #1) for column #1, in which row should the queen be placed? 1 2 3 4 5 6 7 8 for column #2, in which row should the queen be placed? 1 2 3 4 5 6 7 8

8 Queens So, why are we using backtracking? because backtracking allows us to undo previous choices if they turn out to be mistakes Notice that as we choose which row to place each queen, we don’t actually know if our choices will lead to a solution we might be wrong! If we are wrong, we want to undo the minimum number of choices necessary to get back on the right track this also saves as much previous work as possible

8 Queens It’s clear that we could explore the possible choices for the first column with a loop: for (int row = 1; row <= 8; row++) // explore column 1 So we could solve the whole problem with nested loops somewhat like this: for (int row = 1; row <= 8; row++) // column 1 for (int row = 1; row <= 8; row++) // column 2 for (int row = 1; row <= 8; row++) // column 3 ... for (int row = 1; row <= 8; row++) // column 8 But we can write this more elegantly with recursion

8 Queens Recursive backtracking problems have somewhat of a general form This form is easier to see (and the code is easier to understand) if we remove some of the low-level details from our recursive backtracking code To do this, we’ll be using some code Stuart Reges wrote. Stuart’s code is based off code written by one of his former colleagues named Steve Fisher We’re going to use this code to solve N Queens just like 8 queens, but now we can have N queens on an NxN board (where N is any positive number)

N Queens What low-level methods do we need for N Queens? We need a constructor that takes a size (to specify N): public Board(int size) We need to know if it’s safe to place a queen at a location public boolean safe(int row, int col) We need to be able to place a queen on the board public void place(int row, int col) We need to be able to remove a queen from the board, because we might make mistakes and need to backtrack public void remove(int row, int col) And we need some general information about the board public void print() public int size()

N Queens Assume we have all the previous code With that taken care of, we just have to find a solution! easy, right? Let’s write a method called solve to do this: public static void solve(Board b) { ... } Unfortunately, solve doesn’t have enough parameters for us to do our recursion so let’s make a private helper method

N Queens Our private helper method: What parameters does explore need? private static boolean explore(...) { ... } What parameters does explore need?

N Queens Our private helper method: What parameters does explore need? private static boolean explore(...) { ... } What parameters does explore need? it needs a Board to place queens on it needs a column to explore this is a little tricky to see, but this will let each method invocation work on a different column Updated helper method: private static boolean explore(Board b, int col) {

N Queens Well, now what? We don’t want to waste our time exploring dead ends so, if someone wants us to explore column #4, we should require that columns #1, #2, and #3 all have queens and that these three queens don’t threaten each other we’ll make this a precondition (it’s a private method, after all) So, now our helper method has a precondition: // pre : queens have been safely placed in previous // columns

N Queens Time to write our method // pre : queens have been safely placed in previous columns private static boolean explore(Board b, int col) { We know it’s going to be recursive, so we need at least: a base case a recursive case Let’s think about the base case first What column would be nice to get to? When are we done?

N Queens Time to write our method We know it’s going to be recursive, so we need at least: a base case a recursive case Let’s think about the base case first What column would be nice to get to? When are we done? For 8 Queens, column 9 (queens 1 to 8 placed safely) column 8 is almost correct, but remember that if we’re asked to explore column 8, the 8th queen hasn’t yet been placed For N Queens, column N+1 (queens 1 to N placed safely)

N Queens This is our base case! Let’s update our helper code to include it: // pre : queens have been safely placed in previous columns private static boolean explore(Board b, int col) { if (col > b.size()) { return true; } else { ... } Well, that was easy What about our recursive case?

N Queens For our recursive case, suppose we’ve already placed queens in previous columns We want to try placing a queen in all possible rows for the current column We can try all possible rows using a simple for loop: for (int row = 1; row <= board.size(); row++) { ... } This is the same for loop from before! remember, even though we’re using recursion, we still want to use loops when appropriate

N Queens When do we want to try placing a queen at a row for the specified column? only when it is safe to do so! otherwise this location is already threatened and won’t lead us to a solution We can update our code: for (int row = 1; row <= board.size(); row++) { if (b.safe(row, col)) { ... } We’ve picked our location and determined that it’s safe now what?

N Queens // pre : queens have been safely placed in previous columns private static boolean explore(Board b, int col) { if (col > b.size()) { return true; } else { for (int row = 1; row <= board.size(); row++) { if (b.safe(row, col)) { }

N Queens We need to place a queen at this spot and decide if we can reach a solution from here if only we had a method that would explore a Board from the next column and decide if there’s a solution... oh wait! That’s what we’re writing We can update our code to place a queen and recurse: for (int row = 1; row <= board.size(); row++) { if (b.safe(row, col)) { b.place(row, col); explore(b, col + 1); ... } You might be tempted to write col++ here instead, but that won’t work. Why not?

N Queens Also, we don’t want to call explore quite like that explore returns a boolean, telling us whether or not we succeeded in finding a solution (true if found, false otherwise) What should we do if explore returns true? stop exploring and return true (a solution has been found) What should we do if explore returns false? well, the queens we’ve placed so far don’t lead to a solution so, we should remove the queen we placed most recently and try putting it somewhere else

N Queens Updated code: for (int row = 1; row <= board.size(); row++) { if (b.safe(row, col)) { b.place(row, col); if (explore(b, col + 1)) { return true; } b.remove(row, col); We’re almost done. What should we do if we’ve tried placing a queen at every row for this column, and no location leads to a solution? No solution exists, so we should return false This pattern (make a choice, recurse, undo the choice) is really common in recursive backtracking

N Queens Solution And we’re done! Here’s the final code for explore: // pre : queens have been safely placed in previous columns private static boolean explore(Board b, int col) { if (col > b.size()) { return true; } else { for (int row = 1; row <= board.size(); row++) { if (b.safe(row, col)) { b.place(row, col); if (explore(b, col + 1)) { } b.remove(row, col); return false;

N Queens Well, actually we still need to write solve don’t worry, it’s easy! We’ll have solve print out the solution if explore finds one. Otherwise, we’ll have it tell us there’s no solution Code for solve: public static void solve(Board b) { if (explore(b, 1)) { System.out.println(“One solution is as follows:”); b.print(); } else { System.out.println(“No solution”); }

N Queens We’re really done and everything works try running the code yourself! I think it’s pretty cool that such succinct code can do so much There’s also an animated version of the code it shows the backtracking process in great detail if you missed lecture (or if you just want to see the animation again), download queens.zip from the class website and run Queens2.java