#ifndef DLX_DLX_HPP_ #define DLX_DLX_HPP_ #include #include #include namespace dlx { class Dlx final { struct Cell { Cell *U, *D, *L, *R; std::size_t n; union { Cell* c; std::size_t s; }; 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(); }; std::vector ctab_; std::vector 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(); Dlx(Dlx const&) = delete; auto operator=(Dlx const&) -> Dlx& = delete; Dlx(Dlx &&); auto operator=(Dlx &&) -> Dlx&; // 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; // Removes a row from consideration. // Should only be called after all dlx_set() calls. auto RemoveRow(std::size_t row) -> void; // Picks a row to be part of the solution. // Should only be called after all Set() calls and RemoveRows() calls. // TODO: Check the row can be legally chosen. auto PickRow(std::size_t row) -> void; auto Solve( std::function try_cb, std::function undo_cb, std::function found_cb, std::function stuck_cb) -> void; }; auto ForallCover(Dlx& dlx, auto cb) { std::vector 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