Adobe Source Libraries 1.49.0
A collection of C++ libraries.
Loading...
Searching...
No Matches
dancing_links.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013 Adobe
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5*/
6/**************************************************************************************************/
7
8#ifndef ADOBE_dancing_links_t_HPP
9#define ADOBE_dancing_links_t_HPP
10
11/**************************************************************************************************/
12
13#include <adobe/config.hpp>
14
15#include <vector>
16
17#if ADOBE_STD_SERIALIZATION
18#include <iostream>
19#endif
20
21#include <boost/noncopyable.hpp>
22
23#include <adobe/implementation/toroid.hpp>
24
25#define ADOBE_DLX_VERBOSE 0
26
27#if ADOBE_STD_SERIALIZATION && ADOBE_DLX_VERBOSE
28#include <adobe/iomanip.hpp>
29#endif
30
31/**************************************************************************************************/
32
33namespace adobe {
34
35/**************************************************************************************************/
36
37#ifndef ADOBE_NO_DOCUMENTATION
38
39/**************************************************************************************************/
40
41namespace implementation {
42
43/**************************************************************************************************/
44
45struct do_nothing_callback_t {
46 inline void operator()(std::size_t, bool) const {}
47};
48
49/**************************************************************************************************/
50
51struct select_right_heuristic_t {
52 inline toroid_header_t* operator()(byte_toroid_t& toroid) const {
53 return toroid.right_of(&toroid.header_m);
54 }
55};
56
57/**************************************************************************************************/
58
59struct select_most_constrained_heuristic_t {
60 inline toroid_header_t* operator()(byte_toroid_t& toroid) const {
61 toroid_header_t* c(toroid.right_of(&toroid.header_m));
62 std::size_t sz(c->size_m);
63
64 for (toroid_header_t* p(toroid.right_of(c)); p != &toroid.header_m;
65 p = toroid.right_of(p)) {
66 if (p->size_m < sz) {
67 c = p;
68 sz = p->size_m;
69 }
70
71 if (sz == 1)
72 break;
73 }
74
75 return c;
76 }
77};
78
79/**************************************************************************************************/
80
81} // namespace implementation
82
83/**************************************************************************************************/
84
85#endif
86
87/**************************************************************************************************/
88
89class dancing_links_t : boost::noncopyable {
90public:
91#ifndef ADOBE_NO_DOCUMENTATION
92 dancing_links_t(std::size_t row_count, std::size_t column_count)
93 : toroid_m(row_count, column_count), output_m(column_count, 0), solutions_m(0)
95 ,
96 tab_count_m(0)
97#endif
98 {
99 }
100#endif
101
102 inline void set(std::size_t row, std::size_t col, char color = 0) {
103 toroid_m.set(row, col, color);
104 }
105
106 inline void set_secondary_column(std::size_t col) { toroid_m.set_secondary_column(col); }
107
108 template <typename ResultCallback, typename SearchHeuristic>
109 inline std::size_t search(std::size_t max_solutions, ResultCallback callback,
110 SearchHeuristic heuristic) {
111 max_solutions_m = max_solutions;
112
113 toroid_m.finalize();
114
115 do_search(0, callback, heuristic);
116
117 return solutions_m;
118 }
119
120 inline std::size_t search(std::size_t max_solutions) {
121 return search(max_solutions, implementation::do_nothing_callback_t(),
122 implementation::select_most_constrained_heuristic_t());
123 }
124
125#if ADOBE_STD_SERIALIZATION
126 friend std::ostream& operator<<(std::ostream& s, const dancing_links_t& dancing_links_t) {
127 return s << dancing_links_t.toroid_m;
128 }
129#endif
130
131private:
132 template <typename ResultCallback, typename SearchHeuristic>
133 void do_search(std::size_t k, ResultCallback callback, SearchHeuristic heuristic) {
134 if (toroid_m.right_of(&toroid_m.header_m) == &toroid_m.header_m) {
135 ++solutions_m;
136
137#if ADOBE_DLX_VERBOSE
138 std::cout << adobe::indents(tab_count_m) << "<solved/>" << std::endl;
139#endif
140
141 for (std::size_t i(0); i < k; ++i)
142 callback(toroid_m.row_index_of(output_m[i]), i + 1 == k);
143
144 return;
145 }
146
147 std::size_t next_k(k + 1);
148
149 toroid_header_t* c(heuristic(toroid_m));
150
151#if ADOBE_DLX_VERBOSE
152 ++tab_count_m;
153 std::cout << adobe::indents(tab_count_m) << "<c"
154 << toroid_m.column_index_of(toroid_m.down_of(c)) << ">" << std::endl;
155#endif
156
157 toroid_m.cover_column(c);
158
159 // branch on each node in this column
160 for (toroid_node_t* r(toroid_m.down_of(c)); r != c; r = toroid_m.down_of(r)) {
161#if ADOBE_DLX_VERBOSE
162 std::cout << adobe::indents(tab_count_m) << "<r" << toroid_m.row_index_of(r) << ">"
163 << std::endl;
164#endif
165
166 output_m[k] = r;
167
168 // cover or purify each node on the same row as the node we're branching on
169 for (toroid_node_t* j(toroid_m.right_of(r)); j != r; j = toroid_m.right_of(j)) {
170 if (j->color_m == 0) {
171#if ADOBE_DLX_VERBOSE
172 std::cout << adobe::indents(tab_count_m) << "<c" << toroid_m.column_index_of(j)
173 << ">" << std::endl;
174#endif
175 toroid_m.cover_column(toroid_m.column_of(j));
176 } else if (j->color_m > 0) {
177#if ADOBE_DLX_VERBOSE
178 std::cout << adobe::indents(tab_count_m) << "<p" << toroid_m.column_index_of(j)
179 << ">" << std::endl;
180#endif
181 toroid_m.purify(j);
182 }
183 }
184
185#if ADOBE_DLX_VERBOSE
186// std::cout << *this << std::endl;
187#endif
188
189 do_search(next_k, callback, heuristic);
190
191 if (solutions_m >= max_solutions_m)
192 return;
193
194 r = output_m[k];
195
196 c = toroid_m.column_of(r);
197
198 // undo the cover/purify
199 for (toroid_node_t* j(toroid_m.left_of(r)); j != r; j = toroid_m.left_of(j)) {
200 if (j->color_m == 0) {
201#if ADOBE_DLX_VERBOSE
202 std::cout << adobe::indents(tab_count_m) << "</c" << toroid_m.column_index_of(j)
203 << ">" << std::endl;
204#endif
205 toroid_m.uncover_column(toroid_m.column_of(j));
206 } else if (j->color_m > 0) {
207#if ADOBE_DLX_VERBOSE
208 std::cout << adobe::indents(tab_count_m) << "</p" << toroid_m.column_index_of(j)
209 << ">" << std::endl;
210#endif
211 toroid_m.unpurify(j);
212 }
213 }
214
215#if ADOBE_DLX_VERBOSE
216 std::cout << adobe::indents(tab_count_m) << "</r" << toroid_m.row_index_of(r) << ">"
217 << std::endl;
218#endif
219 }
220
221 toroid_m.uncover_column(c);
222
223#if ADOBE_DLX_VERBOSE
224 std::cout << adobe::indents(tab_count_m) << "</c"
225 << toroid_m.column_index_of(toroid_m.down_of(c)) << ">" << std::endl;
226 --tab_count_m;
227#endif
228 };
229
230 byte_toroid_t toroid_m;
231 std::vector<toroid_node_t*> output_m;
232 std::size_t solutions_m;
233 std::size_t max_solutions_m;
234#if ADOBE_DLX_VERBOSE
235 std::size_t tab_count_m;
236#endif
237};
238
239/**************************************************************************************************/
240
241} // namespace adobe
242
243/**************************************************************************************************/
244
245#endif
246
247/**************************************************************************************************/
std::ostream & operator<<(std::ostream &s, const extents_t &x)