CSE 143 Lecture 12 Recursive Backtracking

Slides:



Advertisements
Similar presentations
Copyright 2010 by Pearson Education Building Java Programs Chapter 7 Lecture 7-2: Arrays as Parameters reading: , 3.3 self-checks: Ch. 7 #5, 8,
Advertisements

Building Java Programs
Announcements Assignment #4 is due tonight. Last lab program is going to be assigned this Wednesday. ◦ A backtracking problem.
Arrays part 2 Applications & such. Returning an array from a method A method can return an array, just like it can return any other kind of variable;
Building Java Programs
CSE 143 Lecture 18 Binary Trees read slides created by Marty Stepp and Hélène Martin
Backtracking COP Backtracking  Backtracking is a technique used to solve problems with a large search space, by systematically trying and eliminating.
CSE 143 Lecture 19 Binary Trees read slides created by Marty Stepp
CS 206 Introduction to Computer Science II 10 / 14 / 2009 Instructor: Michael Eckmann.
Backtracking.
Building Java Programs
19-Aug-15 Simple Recursive Algorithms. 2 A short list of categories Algorithm types we will consider include: Simple recursive algorithms Backtracking.
Building Java Programs Chapter 12 Recursion Copyright (c) Pearson All rights reserved.
CSE 143 Lecture 11 Recursive Programming reading: slides created by Marty Stepp and Hélène Martin
Recursion A method is recursive if it makes a call to itself. A method is recursive if it makes a call to itself. For example: For example: public void.
Lecture 5: Backtracking Depth-First Search N-Queens Problem Hamiltonian Circuits.
CSE 143 Lecture 17 More Recursive Backtracking reading: "Appendix R" on course web site slides created by Marty Stepp and Hélène Martin
CSE 143 Lecture 17 More Recursive Backtracking reading: "Appendix R" on course web site slides created by Marty Stepp and Hélène Martin
CSE 143 Lecture 18 Binary Trees read slides created by Marty Stepp
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.
CSE 143 Lecture 18 More Recursive Backtracking slides created by Marty Stepp
CSE 143 Lecture 19 Binary Trees read slides created by Marty Stepp
Analysis & Design of Algorithms (CSCE 321)
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.
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.
CSG3F3/ Desain dan Analisis Algoritma
Problem Solving: Brute Force Approaches
Lecture 19: Binary Trees reading: 17.1 – 17.3
BackTracking CS255.
Depth-First Search N-Queens Problem Hamiltonian Circuits
Recursion A problem solving technique where an algorithm is defined in terms of itself A recursive method is a method that calls itself A recursive algorithm.
CSE 341 Lecture 5 efficiency issues; tail recursion; print
read: 12.5 Lecture 17: recursive backtracking
Midterm Review Problems
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
slides created by Marty Stepp and Alyssa Harding
Building Java Programs
Recursion Copyright (c) Pearson All rights reserved.
Problem Solving: Brute Force Approaches
Another problem to solve…
Building Java Programs
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.
CSE 143 Lecture 11 Recursive Programming reading:
Exercise: Dice roll sum
CSE 143 Lecture 17 Recursive Backtracking
Road Map - Quarter CS Concepts Data Structures Java Language
CSE 143 Lecture 17 Recursive Backtracking
CSE 143 Lecture 15 Recursive Backtracking
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
Counting II: Recurring Problems And Correspondences
Quicksort.
Recursion James Brucker.
Road Map - Quarter CS Concepts Data Structures Java Language
CSE 143 Lecture 18 More Recursive Backtracking
Backtracking and Branch-and-Bound
CSE 143 Lecture 13 Recursive Programming reading:
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
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"?
Announcements Assignment #4 is due tonight. Last lab program is going to be assigned this Wednesday. ◦ A backtracking problem.
Quicksort.
Presentation transcript:

CSE 143 Lecture 12 Recursive Backtracking reading: "Appendix R" on course web site slides adapted from Marty Stepp and Hélène Martin http://www.cs.washington.edu/143/ ideas and examples taken from Stanford University CS slides/lectures

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 combinations of values that could appear on the dice. diceRoll(2); diceRoll(3); [1, 1] [1, 2] [1, 3] [1, 4] [1, 5] [1, 6] [2, 1] [2, 2] [2, 3] [2, 4] [2, 5] [2, 6] [3, 1] [3, 2] [3, 3] [3, 4] [3, 5] [3, 6] [4, 1] [4, 2] [4, 3] [4, 4] [4, 5] [4, 6] [5, 1] [5, 2] [5, 3] [5, 4] [5, 5] [5, 6] [6, 1] [6, 2] [6, 3] [6, 4] [6, 5] [6, 6] [1, 1, 1] [1, 1, 2] [1, 1, 3] [1, 1, 4] [1, 1, 5] [1, 1, 6] [1, 2, 1] [1, 2, 2] ... [6, 6, 4] [6, 6, 5] [6, 6, 6] 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 We want to generate all possible sequences of values. for (each possible first die value): for (each possible second die value): for (each possible third die value): ... print! This is called a depth-first search How can we completely explore such a large search space?

Backtracking backtracking: Finding solution(s) by trying partial solutions and then abandoning them if they are not suitable. a "brute force" algorithmic technique (tries all paths) often 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

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. Explore the remaining choices. Un-make choice C, if necessary. (backtrack!)

A decision tree chosen available - 4 dice 1 3 dice 2 3 dice ... 1, 1 1, 2 2 dice 1, 3 2 dice 1, 4 2 dice ... ... ... 1, 1, 1 1 die 1, 1, 2 1 die 1, 1, 3 1 die 1, 4, 1 1 die ... ... 1, 1, 1, 1 1, 1, 1, 2 ... 1, 1, 3, 1 1, 1, 3, 2 ...

Private helpers Often the method doesn't accept the parameters you want. So write a private helper that accepts more parameters. Extra params can represent current state, choices made, etc. public int methodName(params): ... return helper(params, moreParams); private int helper(params, moreParams): (use moreParams to help solve the problem)

Exercise solution // Prints all possible outcomes of rolling the given // number of six-sided dice in [#, #, #] format. public static void diceRolls(int dice) { List<Integer> chosen = new ArrayList<Integer>(); diceRolls(dice, chosen); } // private recursive helper to implement diceRolls logic private static void diceRolls(int dice, List<Integer> chosen) { if (dice == 0) { System.out.println(chosen); // base case } else { for (int i = 1; i <= 6; i++) { chosen.add(i); // choose diceRolls(dice - 1, chosen); // explore chosen.remove(chosen.size() - 1); // un-choose

Exercise: Dice roll sum Write a method diceSum similar to diceRoll, but it also accepts a desired sum and prints only combinations that add up to exactly that sum. diceSum(2, 7); diceSum(3, 7); [1, 6] [2, 5] [3, 4] [4, 3] [5, 2] [6, 1] [1, 1, 5] [1, 2, 4] [1, 3, 3] [1, 4, 2] [1, 5, 1] [2, 1, 4] [2, 2, 3] [2, 3, 2] [2, 4, 1] [3, 1, 3] [3, 2, 2] [3, 3, 1] [4, 1, 2] [4, 2, 1] [5, 1, 1] 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.

New decision tree chosen available desired sum - 3 dice 5 1 2 dice 2 4 2 dice 5 2 dice 6 2 dice 1, 1 1 die 1, 2 1 die 1, 3 1 die 1, 4 1 die 1, 5 1 die 1, 6 1 die 1, 1, 1 1, 1, 2 1, 1, 3 1, 1, 4 1, 1, 5 1, 1, 6 1, 6, 1 1, 6, 2 ...

Optimizations We need not visit every branch of the decision tree. Some branches are clearly not going to lead to success. We can preemptively stop, or prune, these branches. Inefficiencies in our dice sum algorithm: Sometimes the current sum is already too high. (Even rolling 1 for all remaining dice would exceed the desired sum.) Sometimes the current sum is already too low. (Even rolling 6 for all remaining dice would exceed the desired sum.) When finished, the code must compute the sum every time. (1+1+1 = ..., 1+1+2 = ..., 1+1+3 = ..., 1+1+4 = ..., ...)

Exercise solution, improved public static void diceSum(int dice, int desiredSum) { List<Integer> chosen = new ArrayList<Integer>(); diceSum(dice, desiredSum, chosen, 0); } private static void diceSum(int dice, int desiredSum, List<Integer> chosen, int sumSoFar) { if (dice == 0) { if (sumSoFar == desiredSum) { System.out.println(chosen); } else if (sumSoFar <= desiredSum && sumSoFar + 6 * dice >= desiredSum) { for (int i = 1; i <= 6; i++) { chosen.add(i); diceSum(dice - 1, desiredSum, chosen, sumSoFar + i); chosen.remove(chosen.size() - 1);

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, what should I do? How do I "un-make" a choice?

Exercise: Permutations 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("TEAM") outputs the following sequence of lines: TEAM TEMA TAEM TAME TMEA TMAE ETAM ETMA EATM EAMT EMTA EMAT ATEM ATME AETM AEMT AMTE AMET MTEA MTAE META MEAT MATE MAET 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 We want to generate all possible sequences of letters. for (each possible first letter): for (each possible second letter): for (each possible third letter): ... print! Each permutation is 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

Decision tree chosen available T E A M T E A M E T A M ... T E A M T A E M T M E A T E A M T E M A T A E M T A M E T M E A T M A E T E A M T E M A T A E M T A M E T M E A T M A E

Exercise solution // Outputs all permutations of the given string. public static void permute(String s) { permute(s, ""); } private static void permute(String s, String chosen) { if (s.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 < s.length(); i++) { char c = s.charAt(i); // choose s = s.substring(0, i) + s.substring(i + 1); chosen += c; permute(s, chosen); // explore s = s.substring(0, i) + c + s.substring(i + 1); chosen = chosen.substring(0, chosen.length() - 1); } // un-choose

Exercise solution 2 // Outputs all permutations of the given string. public static void permute(String s) { permute(s, ""); } private static void permute(String s, String chosen) { if (s.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 < s.length(); i++) { String ch = s.substring(i, i + 1); // choose String rest = s.substring(0, i) + // remove s.substring(i + 1); permute(rest, chosen + ch); // explore } // (don't need to "un-choose" because } // we used temp variables)

Exercise: Combinations Write a method combinations that accepts a string s and an integer k as parameters and outputs all possible k -letter words that can be formed from unique letters in that string. The arrangements may be output in any order. Example: combinations("GOOGLE", 3) outputs the sequence of lines at right. To simplify the problem, you may assume that the string s contains at least k unique characters. EGL EGO ELG ELO EOG EOL GEL GEO GLE GLO GOE GOL LEG LEO LGE LGO LOE LOG OEG OEL OGE OGL OLE OLG

Initial attempt Problem: Prints same string multiple times. public static void combinations(String s, int length) { combinations(s, "", length); } private static void combinations(String s, String chosen, int length) { if (length == 0) { System.out.println(chosen); // base case: no choices left } else { for (int i = 0; i < s.length(); i++) { String ch = s.substring(i, i + 1); if (!chosen.contains(ch)) { String rest = s.substring(0, i) + s.substring(i + 1); combinations(rest, chosen + ch, length - 1); Problem: Prints same string multiple times.

Exercise solution public static void combinations(String s, int length) { Set<String> all = new TreeSet<String>(); combinations(s, "", all, length); for (String comb : all) { System.out.println(comb); } private static void combinations(String s, String chosen, Set<String> all, int length) { if (length == 0) { all.add(chosen); // base case: no choices left } else { for (int i = 0; i < s.length(); i++) { String ch = s.substring(i, i + 1); if (!chosen.contains(ch)) { String rest = s.substring(0, i) + s.substring(i + 1); combinations(rest, chosen + ch, all, length - 1);