dancing_links.hpp
Go to the documentation of this file.
00001 /* 00002 Copyright 2005-2007 Adobe Systems Incorporated 00003 Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt 00004 or a copy at http://stlab.adobe.com/licenses.html) 00005 */ 00006 00007 /****************************************************************************************************/ 00008 00009 #ifndef ADOBE_dancing_links_t_HPP 00010 #define ADOBE_dancing_links_t_HPP 00011 00012 /****************************************************************************************************/ 00013 00014 #include <adobe/config.hpp> 00015 00016 #include <vector> 00017 00018 #if ADOBE_STD_SERIALIZATION 00019 #include <iostream> 00020 #endif 00021 00022 #include <boost/function.hpp> 00023 #include <boost/noncopyable.hpp> 00024 00025 #include <adobe/implementation/toroid.hpp> 00026 00027 #define ADOBE_DLX_VERBOSE 0 00028 00029 #if ADOBE_STD_SERIALIZATION && ADOBE_DLX_VERBOSE 00030 #include <adobe/iomanip.hpp> 00031 #endif 00032 00033 /****************************************************************************************************/ 00034 00035 namespace adobe { 00036 00037 /****************************************************************************************************/ 00038 00039 #ifndef ADOBE_NO_DOCUMENTATION 00040 00041 /****************************************************************************************************/ 00042 00043 namespace implementation { 00044 00045 /****************************************************************************************************/ 00046 00047 struct do_nothing_callback_t 00048 { 00049 inline void operator () (std::size_t, bool) const 00050 { } 00051 }; 00052 00053 /****************************************************************************************************/ 00054 00055 struct select_right_heuristic_t 00056 { 00057 inline toroid_header_t* operator () (byte_toroid_t& toroid) const 00058 { return toroid.right_of(&toroid.header_m); } 00059 }; 00060 00061 /****************************************************************************************************/ 00062 00063 struct select_most_constrained_heuristic_t 00064 { 00065 inline toroid_header_t* operator () (byte_toroid_t& toroid) const 00066 { 00067 toroid_header_t* c(toroid.right_of(&toroid.header_m)); 00068 std::size_t sz(c->size_m); 00069 00070 for (toroid_header_t* p(toroid.right_of(c)); p != &toroid.header_m; p = toroid.right_of(p)) 00071 { 00072 if (p->size_m < sz) 00073 { 00074 c = p; 00075 sz = p->size_m; 00076 } 00077 00078 if (sz == 1) break; 00079 } 00080 00081 return c; 00082 } 00083 }; 00084 00085 /****************************************************************************************************/ 00086 00087 } // namespace implementation 00088 00089 /****************************************************************************************************/ 00090 00091 #endif 00092 00093 /****************************************************************************************************/ 00094 00095 class dancing_links_t : boost::noncopyable 00096 { 00097 public: 00098 #ifndef ADOBE_NO_DOCUMENTATION 00099 dancing_links_t(std::size_t row_count, std::size_t column_count) : 00100 toroid_m(row_count, column_count), 00101 output_m(column_count, 0), 00102 solutions_m(0) 00103 #if ADOBE_DLX_VERBOSE 00104 , tab_count_m(0) 00105 #endif 00106 { } 00107 #endif 00108 00109 inline void set(std::size_t row, std::size_t col, char color = 0) 00110 { toroid_m.set(row, col, color); } 00111 00112 inline void set_secondary_column(std::size_t col) 00113 { toroid_m.set_secondary_column(col); } 00114 00115 template <typename ResultCallback, typename SearchHeuristic> 00116 inline std::size_t search(std::size_t max_solutions, 00117 ResultCallback callback, 00118 SearchHeuristic heuristic) 00119 { 00120 max_solutions_m = max_solutions; 00121 00122 toroid_m.finalize(); 00123 00124 do_search(0, callback, heuristic); 00125 00126 return solutions_m; 00127 } 00128 00129 inline std::size_t search(std::size_t max_solutions) 00130 { 00131 return search(max_solutions, 00132 implementation::do_nothing_callback_t(), 00133 implementation::select_most_constrained_heuristic_t()); 00134 } 00135 00136 #if ADOBE_STD_SERIALIZATION 00137 friend std::ostream& operator<<(std::ostream& s, const dancing_links_t& dancing_links_t) 00138 { return s << dancing_links_t.toroid_m; } 00139 #endif 00140 00141 private: 00142 template <typename ResultCallback, typename SearchHeuristic> 00143 void do_search(std::size_t k, ResultCallback callback, SearchHeuristic heuristic) 00144 { 00145 if (toroid_m.right_of(&toroid_m.header_m) == &toroid_m.header_m) 00146 { 00147 ++solutions_m; 00148 00149 #if ADOBE_DLX_VERBOSE 00150 std::cout << adobe::indents(tab_count_m) << "<solved/>" << std::endl; 00151 #endif 00152 00153 for (std::size_t i(0); i < k; ++i) 00154 callback(toroid_m.row_index_of(output_m[i]), i + 1 == k); 00155 00156 return; 00157 } 00158 00159 std::size_t next_k(k + 1); 00160 00161 toroid_header_t* c(heuristic(toroid_m)); 00162 00163 #if ADOBE_DLX_VERBOSE 00164 ++tab_count_m; 00165 std::cout << adobe::indents(tab_count_m) << "<c" << toroid_m.column_index_of(toroid_m.down_of(c)) << ">" << std::endl; 00166 #endif 00167 00168 toroid_m.cover_column(c); 00169 00170 // branch on each node in this column 00171 for (toroid_node_t* r(toroid_m.down_of(c)); r != c; r = toroid_m.down_of(r)) 00172 { 00173 #if ADOBE_DLX_VERBOSE 00174 std::cout << adobe::indents(tab_count_m) << "<r" << toroid_m.row_index_of(r) << ">" << std::endl; 00175 #endif 00176 00177 output_m[k] = r; 00178 00179 // cover or purify each node on the same row as the node we're branching on 00180 for (toroid_node_t* j(toroid_m.right_of(r)); j != r; j = toroid_m.right_of(j)) 00181 { 00182 if (j->color_m == 0) 00183 { 00184 #if ADOBE_DLX_VERBOSE 00185 std::cout << adobe::indents(tab_count_m) << "<c" << toroid_m.column_index_of(j) << ">" << std::endl; 00186 #endif 00187 toroid_m.cover_column(toroid_m.column_of(j)); 00188 } 00189 else if (j->color_m > 0) 00190 { 00191 #if ADOBE_DLX_VERBOSE 00192 std::cout << adobe::indents(tab_count_m) << "<p" << toroid_m.column_index_of(j) << ">" << std::endl; 00193 #endif 00194 toroid_m.purify(j); 00195 } 00196 } 00197 00198 #if ADOBE_DLX_VERBOSE 00199 // std::cout << *this << std::endl; 00200 #endif 00201 00202 do_search(next_k, callback, heuristic); 00203 00204 if (solutions_m >= max_solutions_m) 00205 return; 00206 00207 r = output_m[k]; 00208 00209 c = toroid_m.column_of(r); 00210 00211 // undo the cover/purify 00212 for (toroid_node_t* j(toroid_m.left_of(r)); j != r; j = toroid_m.left_of(j)) 00213 { 00214 if (j->color_m == 0) 00215 { 00216 #if ADOBE_DLX_VERBOSE 00217 std::cout << adobe::indents(tab_count_m) << "</c" << toroid_m.column_index_of(j) << ">" << std::endl; 00218 #endif 00219 toroid_m.uncover_column(toroid_m.column_of(j)); 00220 } 00221 else if (j->color_m > 0) 00222 { 00223 #if ADOBE_DLX_VERBOSE 00224 std::cout << adobe::indents(tab_count_m) << "</p" << toroid_m.column_index_of(j) << ">" << std::endl; 00225 #endif 00226 toroid_m.unpurify(j); 00227 } 00228 } 00229 00230 #if ADOBE_DLX_VERBOSE 00231 std::cout << adobe::indents(tab_count_m) << "</r" << toroid_m.row_index_of(r) << ">" << std::endl; 00232 #endif 00233 } 00234 00235 toroid_m.uncover_column(c); 00236 00237 #if ADOBE_DLX_VERBOSE 00238 std::cout << adobe::indents(tab_count_m) << "</c" << toroid_m.column_index_of(toroid_m.down_of(c)) << ">" << std::endl; 00239 --tab_count_m; 00240 #endif 00241 }; 00242 00243 byte_toroid_t toroid_m; 00244 std::vector<toroid_node_t*> output_m; 00245 std::size_t solutions_m; 00246 std::size_t max_solutions_m; 00247 #if ADOBE_DLX_VERBOSE 00248 std::size_t tab_count_m; 00249 #endif 00250 }; 00251 00252 /****************************************************************************************************/ 00253 00254 } // namespace adobe 00255 00256 /****************************************************************************************************/ 00257 00258 #endif 00259 00260 /****************************************************************************************************/ |