2022-11-19 14:59:21 -08:00
|
|
|
#ifndef DLX_DLX_HPP_
|
|
|
|
#define DLX_DLX_HPP_
|
|
|
|
|
|
|
|
#include <cstddef>
|
|
|
|
#include <functional>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace dlx {
|
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
class Dlx final {
|
2022-11-19 14:59:21 -08:00
|
|
|
|
|
|
|
struct Cell {
|
|
|
|
Cell *U, *D, *L, *R;
|
|
|
|
std::size_t n;
|
|
|
|
union {
|
|
|
|
Cell* c;
|
|
|
|
std::size_t s;
|
|
|
|
};
|
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
auto LR_self() -> void;
|
|
|
|
auto UD_self() -> void;
|
|
|
|
auto LR_delete() -> void;
|
|
|
|
auto UD_delete() -> void;
|
|
|
|
auto UD_restore() -> void;
|
|
|
|
auto LR_restore() -> void;
|
|
|
|
auto LR_insert(Cell* k) -> void;
|
|
|
|
auto UD_insert(Cell* k) -> void;
|
|
|
|
auto CoverCol() -> void;
|
|
|
|
auto UncoverCol() -> void;
|
|
|
|
auto ColAdd(std::size_t row_id) -> Cell*;
|
|
|
|
static Cell* ColNew();
|
2022-11-19 14:59:21 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<Cell*> ctab_;
|
|
|
|
std::vector<Cell*> rtab_;
|
|
|
|
Cell* root_;
|
|
|
|
|
|
|
|
auto AddCol() -> void;
|
|
|
|
auto AddRow() -> void;
|
|
|
|
auto AllocCol(std::size_t n) -> void;
|
|
|
|
auto AllocRow(std::size_t n) -> void;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Dlx();
|
|
|
|
~Dlx();
|
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
Dlx(Dlx const&) = delete;
|
|
|
|
auto operator=(Dlx const&) -> Dlx& = delete;
|
|
|
|
|
|
|
|
Dlx(Dlx &&);
|
|
|
|
auto operator=(Dlx &&) -> Dlx&;
|
|
|
|
|
2022-11-19 14:59:21 -08:00
|
|
|
// Returns number of rows.
|
|
|
|
auto Rows() const -> std::size_t;
|
|
|
|
|
|
|
|
// Returns number of columns.
|
|
|
|
auto Cols() const -> std::size_t;
|
|
|
|
|
|
|
|
// Places a 1 in the given row and column.
|
|
|
|
// Increases the number of rows and columns if necessary.
|
|
|
|
auto Set(std::size_t row, std::size_t col) -> void;
|
|
|
|
|
|
|
|
// Marks a column as optional: a solution need not cover the given column,
|
|
|
|
// but it still must respect the constraints it entails.
|
|
|
|
auto MarkOptional(std::size_t col) -> void;
|
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
// Removes a row from consideration.
|
2022-11-19 14:59:21 -08:00
|
|
|
// Should only be called after all dlx_set() calls.
|
2022-11-20 10:09:23 -08:00
|
|
|
auto RemoveRow(std::size_t row) -> void;
|
2022-11-19 14:59:21 -08:00
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
// Picks a row to be part of the solution.
|
|
|
|
// Should only be called after all Set() calls and RemoveRows() calls.
|
2022-11-19 14:59:21 -08:00
|
|
|
// TODO: Check the row can be legally chosen.
|
2022-11-20 10:09:23 -08:00
|
|
|
auto PickRow(std::size_t row) -> void;
|
2022-11-19 14:59:21 -08:00
|
|
|
|
|
|
|
auto Solve(
|
|
|
|
std::function<void(std::size_t, std::size_t, std::size_t)> try_cb,
|
|
|
|
std::function<void()> undo_cb,
|
|
|
|
std::function<void()> found_cb,
|
|
|
|
std::function<void(std::size_t)> stuck_cb) -> void;
|
|
|
|
};
|
|
|
|
|
|
|
|
auto ForallCover(Dlx& dlx, auto cb) {
|
|
|
|
std::vector<std::size_t> sol;
|
|
|
|
dlx.Solve(
|
|
|
|
[&](std::size_t c, std::size_t s, std::size_t r) { sol.push_back(r); },
|
|
|
|
[&](){ sol.pop_back(); },
|
|
|
|
[&](){ cb(sol); },
|
|
|
|
[](std::size_t){}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
#endif
|