dlx: nicer iteration
This commit is contained in:
parent
50640e6adb
commit
234165c7f3
|
@ -7,30 +7,9 @@
|
||||||
|
|
||||||
namespace dlx {
|
namespace dlx {
|
||||||
|
|
||||||
|
struct Cell;
|
||||||
|
|
||||||
class Dlx final {
|
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<Cell*> ctab_;
|
std::vector<Cell*> ctab_;
|
||||||
std::vector<Cell*> rtab_;
|
std::vector<Cell*> rtab_;
|
||||||
Cell* root_;
|
Cell* root_;
|
||||||
|
|
124
dlx/src/dlx.cpp
124
dlx/src/dlx.cpp
|
@ -6,16 +6,76 @@
|
||||||
|
|
||||||
namespace dlx {
|
namespace dlx {
|
||||||
|
|
||||||
auto Dlx::Cell::LR_self() -> void { L = R = this; }
|
template <Cell* Cell::* direction> struct CellView;
|
||||||
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*
|
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 rightwards() -> CellView<&Cell::R>;
|
||||||
|
auto leftwards() -> CellView<&Cell::L>;
|
||||||
|
auto upwards() -> CellView<&Cell::U>;
|
||||||
|
auto downwards() -> CellView<&Cell::D>;
|
||||||
|
|
||||||
|
auto ColAdd(std::size_t row_id) -> Cell*;
|
||||||
|
static Cell* ColNew();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <Cell* Cell::* direction>
|
||||||
|
struct CellView {
|
||||||
|
Cell* cell;
|
||||||
|
|
||||||
|
auto operator==(CellView const&) const -> bool = default;
|
||||||
|
auto begin() const -> CellView;
|
||||||
|
auto end() const -> CellView;
|
||||||
|
auto operator*() -> Cell*;
|
||||||
|
auto operator++() -> CellView&;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <Cell* Cell::* direction>
|
||||||
|
auto CellView<direction>::begin() const -> CellView { return {cell->*direction}; }
|
||||||
|
|
||||||
|
template <Cell* Cell::* direction>
|
||||||
|
auto CellView<direction>::end() const -> CellView { return {cell}; }
|
||||||
|
|
||||||
|
template <Cell* Cell::* direction>
|
||||||
|
auto CellView<direction>::operator*() -> Cell* { return cell; }
|
||||||
|
|
||||||
|
template <Cell* Cell::* direction>
|
||||||
|
auto CellView<direction>::operator++() -> CellView& {
|
||||||
|
cell = cell->*direction;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cell::LR_self() -> void { L = R = this; }
|
||||||
|
auto Cell::UD_self() -> void { U = D = this; }
|
||||||
|
auto Cell::LR_delete() -> void { L->R = R; R->L = L; }
|
||||||
|
auto Cell::UD_delete() -> void { U->D = D; D->U = U; }
|
||||||
|
auto Cell::UD_restore() -> void { U->D = D->U = this; }
|
||||||
|
auto Cell::LR_restore() -> void { L->R = R->L = this; }
|
||||||
|
auto Cell::LR_insert(Cell* k) -> void { L = k->L; R = k; k->L = k->L->R = this; }
|
||||||
|
auto Cell::UD_insert(Cell* k) -> void { U = k->U, D = k, k->U = k->U->D = this; }
|
||||||
|
|
||||||
|
auto Cell::ColNew() -> Cell*
|
||||||
{
|
{
|
||||||
auto c = new Cell;
|
auto c = new Cell;
|
||||||
c->UD_self();
|
c->UD_self();
|
||||||
|
@ -23,7 +83,7 @@ auto Dlx::Cell::ColNew() -> Dlx::Cell*
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Dlx::Cell::ColAdd(std::size_t row_id) -> Cell*
|
auto Cell::ColAdd(std::size_t row_id) -> Cell*
|
||||||
{
|
{
|
||||||
auto n = new Cell;
|
auto n = new Cell;
|
||||||
n->n = row_id;
|
n->n = row_id;
|
||||||
|
@ -33,19 +93,19 @@ auto Dlx::Cell::ColAdd(std::size_t row_id) -> Cell*
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Dlx::Cell::CoverCol() -> void {
|
auto Cell::CoverCol() -> void {
|
||||||
LR_delete();
|
LR_delete();
|
||||||
for (auto i = D; i != this; i = i->D) {
|
for (auto const i : downwards()) {
|
||||||
for (auto j = i->R; j != i; j = j->R) {
|
for (auto const j : i->rightwards()) {
|
||||||
j->UD_delete();
|
j->UD_delete();
|
||||||
j->c->s--;
|
j->c->s--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Dlx::Cell::UncoverCol() -> void {
|
auto Cell::UncoverCol() -> void {
|
||||||
for (auto i = U; i != this; i = i->U) {
|
for (auto const i : upwards()) {
|
||||||
for (auto j = i->L; j != i; j = j->L) {
|
for (auto const j : i->leftwards()) {
|
||||||
j->c->s++;
|
j->c->s++;
|
||||||
j->UD_restore();
|
j->UD_restore();
|
||||||
}
|
}
|
||||||
|
@ -53,7 +113,10 @@ auto Dlx::Cell::UncoverCol() -> void {
|
||||||
LR_restore();
|
LR_restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Cell::rightwards() -> CellView<&Cell::R> { return CellView<&Cell::R>{this}; }
|
||||||
|
auto Cell::leftwards() -> CellView<&Cell::L> { return CellView<&Cell::L>{this}; }
|
||||||
|
auto Cell::upwards() -> CellView<&Cell::U> { return CellView<&Cell::U>{this}; }
|
||||||
|
auto Cell::downwards() -> CellView<&Cell::D> { return CellView<&Cell::D>{this}; }
|
||||||
|
|
||||||
Dlx::Dlx() {
|
Dlx::Dlx() {
|
||||||
root_ = Cell::ColNew();
|
root_ = Cell::ColNew();
|
||||||
|
@ -63,16 +126,18 @@ Dlx::Dlx() {
|
||||||
Dlx::~Dlx() {
|
Dlx::~Dlx() {
|
||||||
for (auto const row : rtab_) {
|
for (auto const row : rtab_) {
|
||||||
if (row) {
|
if (row) {
|
||||||
Cell* next;
|
auto cursor = row->R;
|
||||||
for (auto cursor = row->R; cursor != row; cursor = next) {
|
// manual iteration because we have to save next _before_ deleting cursor
|
||||||
next = cursor->R;
|
while (cursor != row) {
|
||||||
delete cursor;
|
auto tmp = cursor;
|
||||||
|
cursor = cursor->R;
|
||||||
|
delete tmp;
|
||||||
}
|
}
|
||||||
delete row;
|
delete row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto const col : ctab_) {
|
for (auto const col : ctab_) {
|
||||||
if (col) { delete col; }
|
delete col;
|
||||||
}
|
}
|
||||||
delete root_;
|
delete root_;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +183,6 @@ auto Dlx::MarkOptional(std::size_t col) -> void {
|
||||||
c->LR_self();
|
c->LR_self();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto Dlx::Set(std::size_t row, std::size_t col) -> void {
|
auto Dlx::Set(std::size_t row, std::size_t col) -> void {
|
||||||
AllocRow(row);
|
AllocRow(row);
|
||||||
AllocCol(col);
|
AllocCol(col);
|
||||||
|
@ -134,7 +198,7 @@ auto Dlx::Set(std::size_t row, std::size_t col) -> void {
|
||||||
// Ignore duplicates.
|
// Ignore duplicates.
|
||||||
if (r->c->n == col) return;
|
if (r->c->n == col) return;
|
||||||
|
|
||||||
for (auto cursor = r->R; cursor != r; cursor = cursor->R) {
|
for (auto const cursor : r->rightwards()) {
|
||||||
if (cursor->c->n == col) return;
|
if (cursor->c->n == col) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +209,7 @@ auto Dlx::Set(std::size_t row, std::size_t col) -> void {
|
||||||
auto Dlx::PickRow(std::size_t i) -> void {
|
auto Dlx::PickRow(std::size_t i) -> void {
|
||||||
if (auto r = rtab_.at(i)) {
|
if (auto r = rtab_.at(i)) {
|
||||||
r->c->CoverCol();
|
r->c->CoverCol();
|
||||||
for (auto j = r->R; j != r; j = j->R) {
|
for (auto const j : r->rightwards()) {
|
||||||
j->c->CoverCol();
|
j->c->CoverCol();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,7 +219,7 @@ auto Dlx::RemoveRow(std::size_t i) -> void {
|
||||||
if (auto & r = rtab_.at(i)) {
|
if (auto & r = rtab_.at(i)) {
|
||||||
r->UD_delete();
|
r->UD_delete();
|
||||||
r->c->s--;
|
r->c->s--;
|
||||||
for (auto j = r->R; j != r; j = j->R) {
|
for (auto const j : r->rightwards()) {
|
||||||
j->UD_delete();
|
j->UD_delete();
|
||||||
j->c->s--;
|
j->c->s--;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +241,7 @@ auto Dlx::Solve(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s = std::numeric_limits<std::size_t>::max();
|
auto s = std::numeric_limits<std::size_t>::max();
|
||||||
for (auto i = root_->R; i != root_; i = i->R) {
|
for (auto const i : root_->rightwards()) {
|
||||||
if (i->s < s) {
|
if (i->s < s) {
|
||||||
s = (c = i)->s;
|
s = (c = i)->s;
|
||||||
|
|
||||||
|
@ -189,14 +253,14 @@ auto Dlx::Solve(
|
||||||
}
|
}
|
||||||
|
|
||||||
c->CoverCol();
|
c->CoverCol();
|
||||||
for (auto r = c->D; r != c; r = r->D) {
|
for (auto const r : c->downwards()) {
|
||||||
try_cb(c->n, s, r->n);
|
try_cb(c->n, s, r->n);
|
||||||
for (auto j = r->R; j != r; j = j->R) {
|
for (auto const j : r->rightwards()) {
|
||||||
j->c->CoverCol();
|
j->c->CoverCol();
|
||||||
}
|
}
|
||||||
self(self);
|
self(self);
|
||||||
undo_cb();
|
undo_cb();
|
||||||
for (auto j = r->L; j != r; j=j->L) {
|
for (auto const j : r->leftwards()) {
|
||||||
j->c->UncoverCol();
|
j->c->UncoverCol();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user