1. Concept
Backtracking is a refinement of the brute force approach, which systematically searches for a solution to a problem among all available options. It does so by assuming that the solutions are represented by vectors (v1, ..., vm) of values and by traversing, in a depth first manner, the domains of the vectors until the solutions are found.
When invoked, the algorithm starts with an empty vector. At each stage it extends the partial vector with a new value. Upon reaching a partial vector (v1, ..., vi) which can’t represent a partial solution, the algorithm backtracks by removing the trailing value from the vector, and then proceeds by trying to extend the vector with alternative values.
The classic textbook example of the use of backtracking is the eight queens puzzle that asks for all arrangements of eight chess queens on a standard chessboard so that no queen attacks any other.
2. Examples
1) a simple example
recursion:
public int fun(int a, int b){ if(a > 5){ return 2; }else{ int c = fun(a+1, b*2) + a + b; return c; } }
backtracking:
public int backtracking(int a, int b){ Stack<Integer> stack = new Stack<Integer>(); int status = 0; int sum = 0; while(!stack.empty() || status == 0){ if(status == 0){ if( a > 5){ status = 1; sum = 2; }else{ stack.push(a); stack.push(b); a = a + 1; b = b * 2; status = 0; } }else{ b = stack.pop(); a = stack.pop(); sum += a + b; status = 1; } } return sum; }
2) inorder traverse of a binary tree
recursion:
public void inorder(Node root){ if(root == null) return; inorder(root.leftChild); System.out.print(root.data + " "); inorder(root.rightChild); }
backtracking:
public static void backtracking(Node root){ Stack<Node> stack = new Stack<Node>(); boolean status1 = true; while(!stack.empty() || status1 == true){ if(status1 == true){ if(root == null){ status1 = false; continue; } stack.push(root); root = root.leftChild; status1 = true; }else{ root = stack.pop(); System.out.print(root.data + " "); root = root.rightChild; status1 = true; } } }
if we add a statement after the second recursion function as follows:
public void inorder(Node root){ if(root == null) return; inorder(root.leftChild); System.out.print(root.data + " "); inorder(root.rightChild); System.out.print(" finish "); }
then we need to decide where to return
public void backtracking(Node root){ Stack<Node> stack = new Stack<Node>(); Stack<Integer> statusStack = new Stack<Integer>(); int status = 0; while(!stack.empty() || status == 0){ if(status == 0){ if(root == null){ status = statusStack.pop(); continue; } stack.push(root); root = root.leftChild; statusStack.push(1); status = 0; }else if(status == 1){ root = stack.pop(); System.out.print(root.data + " "); root = root.rightChild; stack.push(root); statusStack.push(2); status = 0; }else{ stack.pop(); if(!statusStack.empty()){ status = statusStack.pop(); } System.out.print(" finish "); } } }
3) quicksort
recursion:
public int partition(int[] arr, int begin, int end){ int pivot = arr[begin + (end-begin)/2]; while(begin < end){ while(arr[begin] < pivot){ begin++; } while(arr[end] > pivot){ end--; } if(begin <= end){ int temp = arr[begin]; arr[begin] = arr[end]; arr[end] = temp; begin++; end--; } } return begin; } public void quicksort(int[] arr, int begin, int end){ int pivot = partition(arr, begin, end); if(pivot-1 > begin){ quicksort(arr, begin, pivot -1); } if(pivot < end){ quicksort(arr, pivot, end); } }
backtracking:
public void bactrackingk(int[] arr, int begin, int end){ Stack<Integer> stack = new Stack<Integer>(); int status = 0; while(!stack.empty() || status == 0){ if(status == 0){ int pivot = partition(arr, begin, end); if(pivot-1 <= begin){ status = 1; continue; } stack.push(end); stack.push(pivot); end = pivot - 1; status = 0; }else{ int pivot = stack.pop(); end = stack.pop(); begin = stack.pop(); if(pivot > end){ status = 1; continue; } begin = pivot - 1; status = 0; } } }
more:
http://en.wikipedia.org/wiki/Backtracking
http://web.cse.ohio-state.edu/~gurari/course/cis680/cis680Ch19.html
http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741376.html