Listing 1: An STL-style backtracking functor
#ifndef BackTrack_h #define BackTrack_h template <class T, class I, class V> class BackTrack { public: // precondition: first <= last BackTrack(const T& first, const T& last); // Finds the next solution to the problem. Repeated calls // will find all solutions to a problem if multiple solutions // exist. // Returns true if a solution was found. // // Set first to true to get the first solution. // bool operator() (const I& begin, I end, bool& first); private: // Finds the next valid sibling of the leaf (end-1). // Returns true is if a valid sibling was found. bool FindValidSibling (const I& begin, const I& end); // Backtracks through the decision tree until it finds a node // that hasn't been visited. Returns true if an unvisited // node was found. bool VisitNewNode (const I& begin, I& end); void CreateLeftLeaf (I& end); T left_child; T right_child; V IsValid; }; template <class T, class I, class V> BackTrack<T,I,V>::BackTrack(const T& first, const T& last) : left_child (first), right_child (last) { } template <class T, class I, class V> bool BackTrack<T,I,V>::VisitNewNode(const I& begin, I& end) { // ALGORITHM: // // If the current node is the rightmost child we must // backtrack one level because there are no more children at // this level. So we back up until we find a non-rightmost // child, then generate the child to the right. If we back // up to the top without finding an unvisted child, then all // nodes have been generated. // Back up as long as the node is the rightmost child of // its parent. while (end-begin > 0 && *(end-1) == right_child) --end; I back = end-1; if (end-begin > 0 && *back != right_child) { ++(*back); return true; } else return false; } template <class T, class I, class V> bool BackTrack<T,I,V>::FindValidSibling (const I& begin, const I& end) { // Note that on entry to this routine the leaf has not yet // been used or tested for validity, so the leaf is // considered a "sibling" of itself. I back = end-1; while (true) { if (IsValid (begin, end)) return true; else if (*back != right_child) ++(*back); else return false; } } template <class T, class I, class V> inline void BackTrack<T,I,V>::CreateLeftLeaf (I& end) { *(end++) = left_child; } template <class T, class I, class V> bool BackTrack<T,I,V>::operator () (const I& begin, I end, bool& first) { const int size = end - begin; // If first time, need to create a root. // Otherwise need to visit new node since vector // contains the last solution. if (first) { first = false; end = begin; CreateLeftLeaf (end); } else if (!VisitNewNode (begin, end)) return false; while (true) { if (FindValidSibling (begin, end)) { if (end - begin < size) CreateLeftLeaf (end); else return true; } else if (!VisitNewNode (begin, end)) return false; // the tree has been exhausted, // so no solution exists. } }