2022-11-19 14:59:21 -08:00
|
|
|
// See http://en.wikipedia.org/wiki/Dancing_Links.
|
|
|
|
|
|
|
|
#include "dlx.hpp"
|
|
|
|
|
|
|
|
#include <limits>
|
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
namespace dlx {
|
|
|
|
|
|
|
|
auto Dlx::Cell::LR_self() -> void { L = R = this; }
|
|
|
|
auto Dlx::Cell::UD_self() -> void { U = D = this; }
|
|
|
|
auto Dlx::Cell::LR_delete() -> void { L->R = R; R->L = L; }
|
|
|
|
auto Dlx::Cell::UD_delete() -> void { U->D = D; D->U = U; }
|
|
|
|
auto Dlx::Cell::UD_restore() -> void { U->D = D->U = this; }
|
|
|
|
auto Dlx::Cell::LR_restore() -> void { L->R = R->L = this; }
|
|
|
|
auto Dlx::Cell::LR_insert(Cell* k) -> void { L = k->L; R = k; k->L = k->L->R = this; }
|
|
|
|
auto Dlx::Cell::UD_insert(Cell* k) -> void { U = k->U, D = k, k->U = k->U->D = this; }
|
|
|
|
|
|
|
|
auto Dlx::Cell::ColNew() -> Dlx::Cell*
|
|
|
|
{
|
|
|
|
auto c = new Cell;
|
|
|
|
c->UD_self();
|
|
|
|
c->s = 0;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Dlx::Cell::ColAdd(std::size_t row_id) -> Cell*
|
|
|
|
{
|
|
|
|
auto n = new Cell;
|
|
|
|
n->n = row_id;
|
|
|
|
n->c = this;
|
|
|
|
this->s++;
|
|
|
|
n->UD_insert(this);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Dlx::Cell::CoverCol() -> void {
|
|
|
|
LR_delete();
|
|
|
|
for (auto i = D; i != this; i = i->D) {
|
|
|
|
for (auto j = i->R; j != i; j = j->R) {
|
|
|
|
j->UD_delete();
|
|
|
|
j->c->s--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Dlx::Cell::UncoverCol() -> void {
|
|
|
|
for (auto i = U; i != this; i = i->U) {
|
|
|
|
for (auto j = i->L; j != i; j = j->L) {
|
|
|
|
j->c->s++;
|
|
|
|
j->UD_restore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LR_restore();
|
|
|
|
}
|
2022-11-19 14:59:21 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dlx::Dlx() {
|
|
|
|
root_ = Cell::ColNew();
|
|
|
|
root_->LR_self();
|
|
|
|
}
|
|
|
|
|
|
|
|
Dlx::~Dlx() {
|
|
|
|
for (auto const row : rtab_) {
|
|
|
|
if (row) {
|
|
|
|
Cell* next;
|
|
|
|
for (auto cursor = row->R; cursor != row; cursor = next) {
|
|
|
|
next = cursor->R;
|
|
|
|
delete cursor;
|
|
|
|
}
|
|
|
|
delete row;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto const col : ctab_) {
|
|
|
|
if (col) { delete col; }
|
|
|
|
}
|
|
|
|
delete root_;
|
|
|
|
}
|
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
Dlx::Dlx(Dlx && dlx) : ctab_{}, rtab_{}, root_{}
|
|
|
|
{
|
|
|
|
std::swap(ctab_, dlx.ctab_);
|
|
|
|
std::swap(rtab_, dlx.rtab_);
|
|
|
|
std::swap(root_, dlx.root_);
|
2022-11-19 14:59:21 -08:00
|
|
|
}
|
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
auto Dlx::operator=(Dlx && dlx) -> Dlx& {
|
|
|
|
if (this != &dlx) {
|
|
|
|
this->~Dlx();
|
|
|
|
new (this) Dlx(std::move(dlx));
|
|
|
|
}
|
|
|
|
return *this;
|
2022-11-19 14:59:21 -08:00
|
|
|
}
|
2022-11-20 10:09:23 -08:00
|
|
|
|
|
|
|
auto Dlx::Rows() const -> std::size_t { return rtab_.size(); }
|
|
|
|
auto Dlx::Cols() const -> std::size_t { return ctab_.size(); }
|
|
|
|
|
2022-11-19 14:59:21 -08:00
|
|
|
auto Dlx::AllocCol(std::size_t n) -> void {
|
2022-11-20 10:09:23 -08:00
|
|
|
while(Cols() <= n) {
|
|
|
|
auto c = Cell::ColNew();
|
|
|
|
c->LR_insert(root_);
|
|
|
|
c->n = Cols();
|
|
|
|
ctab_.push_back(c);
|
|
|
|
}
|
2022-11-19 14:59:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Dlx::AllocRow(std::size_t n) -> void {
|
2022-11-20 10:09:23 -08:00
|
|
|
while (Rows() <= n) {
|
|
|
|
rtab_.push_back(nullptr);
|
|
|
|
}
|
2022-11-19 14:59:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Dlx::MarkOptional(std::size_t col) -> void {
|
|
|
|
AllocCol(col);
|
|
|
|
auto c = ctab_[col];
|
|
|
|
// Prevent undeletion by self-linking.
|
|
|
|
c->LR_delete();
|
|
|
|
c->LR_self();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto Dlx::Set(std::size_t row, std::size_t col) -> void {
|
|
|
|
AllocRow(row);
|
|
|
|
AllocCol(col);
|
2022-11-20 10:09:23 -08:00
|
|
|
auto c = ctab_[col];
|
2022-11-19 14:59:21 -08:00
|
|
|
auto & r = rtab_[row];
|
|
|
|
|
|
|
|
if (!r) {
|
2022-11-20 10:09:23 -08:00
|
|
|
r = c->ColAdd(row);
|
2022-11-19 14:59:21 -08:00
|
|
|
r->LR_self();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore duplicates.
|
|
|
|
if (r->c->n == col) return;
|
|
|
|
|
|
|
|
for (auto cursor = r->R; cursor != r; cursor = cursor->R) {
|
|
|
|
if (cursor->c->n == col) return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise insert at end of LR list.
|
2022-11-20 10:09:23 -08:00
|
|
|
c->ColAdd(row)->LR_insert(r);
|
2022-11-19 14:59:21 -08:00
|
|
|
}
|
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
auto Dlx::PickRow(std::size_t i) -> void {
|
|
|
|
if (auto r = rtab_.at(i)) {
|
|
|
|
r->c->CoverCol();
|
|
|
|
for (auto j = r->R; j != r; j = j->R) {
|
|
|
|
j->c->CoverCol();
|
|
|
|
}
|
2022-11-19 14:59:21 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
auto Dlx::RemoveRow(std::size_t i) -> void {
|
|
|
|
if (auto & r = rtab_.at(i)) {
|
|
|
|
r->UD_delete();
|
|
|
|
r->c->s--;
|
|
|
|
for (auto j = r->R; j != r; j = j->R) {
|
|
|
|
j->UD_delete();
|
|
|
|
j->c->s--;
|
|
|
|
}
|
|
|
|
r = nullptr;
|
2022-11-19 14:59:21 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Dlx::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 const recurse = [&](auto const& self) -> void {
|
|
|
|
auto c = root_->R;
|
|
|
|
if (c == root_) {
|
|
|
|
found_cb();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-20 10:09:23 -08:00
|
|
|
auto s = std::numeric_limits<std::size_t>::max();
|
2022-11-19 14:59:21 -08:00
|
|
|
for (auto i = root_->R; i != root_; i = i->R) {
|
|
|
|
if (i->s < s) {
|
|
|
|
s = (c = i)->s;
|
2022-11-20 10:09:23 -08:00
|
|
|
|
|
|
|
if (s == 0) {
|
|
|
|
stuck_cb(c->n);
|
|
|
|
return;
|
|
|
|
}
|
2022-11-19 14:59:21 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c->CoverCol();
|
|
|
|
for (auto r = c->D; r != c; r = r->D) {
|
|
|
|
try_cb(c->n, s, r->n);
|
|
|
|
for (auto j = r->R; j != r; j = j->R) {
|
|
|
|
j->c->CoverCol();
|
|
|
|
}
|
|
|
|
self(self);
|
|
|
|
undo_cb();
|
|
|
|
for (auto j = r->L; j != r; j=j->L) {
|
|
|
|
j->c->UncoverCol();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c->UncoverCol();
|
|
|
|
};
|
|
|
|
recurse(recurse);
|
|
|
|
}
|
2022-11-20 10:09:23 -08:00
|
|
|
|
|
|
|
} // namespace
|