#[derive(Clone, Debug)]
struct Node {
left: usize,
right: usize,
up: usize,
down: usize,
column: usize, }
#[derive(Clone, Debug)]
struct Column {
size: usize,
}
pub struct DancingLinks {
root: usize,
nodes: Vec<Node>,
cols: Vec<Column>,
num_cols: usize,
row_id: Vec<usize>,
solution_stack: Vec<usize>,
}
impl DancingLinks {
pub fn new(matrix: &[Vec<bool>]) -> Self {
let rows = matrix.len();
if rows == 0 {
return DancingLinks {
root: 0,
nodes: vec![Node {
left: 0,
right: 0,
up: 0,
down: 0,
column: 0,
}],
cols: vec![Column { size: 0 }],
num_cols: 0,
row_id: Vec::new(),
solution_stack: Vec::new(),
};
}
let cols = matrix[0].len();
let mut dlx = DancingLinks {
root: 0,
nodes: Vec::new(),
cols: Vec::new(),
num_cols: cols,
row_id: Vec::new(),
solution_stack: Vec::new(),
};
dlx.nodes.reserve(1 + cols); dlx.cols.reserve(cols + 1);
dlx.nodes.push(Node {
left: cols,
right: 1,
up: 0,
down: 0,
column: 0,
});
dlx.cols.push(Column { size: 0 });
for c in 1..=cols {
dlx.nodes.push(Node {
left: if c == 1 { 0 } else { c - 1 },
right: if c == cols { 0 } else { c + 1 },
up: c,
down: c,
column: c,
});
dlx.cols.push(Column { size: 0 });
}
let mut current_node_idx = 1 + cols; for (r, row) in matrix.iter().enumerate() {
let mut first_in_row: Option<usize> = None;
for (c, &value) in row.iter().enumerate() {
if !value {
continue;
}
let col_header_idx = c + 1;
let up_idx = dlx.nodes[col_header_idx].up;
let node_idx = current_node_idx;
current_node_idx += 1;
dlx.nodes.push(Node {
column: col_header_idx,
up: up_idx,
down: col_header_idx,
left: node_idx,
right: node_idx,
});
dlx.row_id.push(r);
dlx.nodes[node_idx].down = col_header_idx;
dlx.nodes[up_idx].down = node_idx;
dlx.nodes[col_header_idx].up = node_idx;
dlx.cols[col_header_idx].size += 1;
if let Some(first) = first_in_row {
let left_idx = dlx.nodes[first].left;
dlx.nodes[node_idx].right = first;
dlx.nodes[node_idx].left = left_idx;
dlx.nodes[left_idx].right = node_idx;
dlx.nodes[first].left = node_idx;
} else {
first_in_row = Some(node_idx);
}
}
}
dlx
}
pub fn solve_all(&mut self) -> Vec<Vec<usize>> {
let mut solutions = Vec::new();
self.search(&mut solutions);
solutions
}
fn search(&mut self, solutions: &mut Vec<Vec<usize>>) {
if self.nodes[self.root].right == self.root {
let mut sol_rows = Vec::with_capacity(self.solution_stack.len());
for &node_idx in &self.solution_stack {
let r = self.row_id[node_idx - (1 + self.num_cols)];
sol_rows.push(r);
}
solutions.push(sol_rows);
return;
}
let col = {
let mut c = self.nodes[self.root].right;
let mut best = c;
let mut best_size = self.cols[c].size;
while c != self.root {
if self.cols[c].size < best_size {
best = c;
best_size = self.cols[c].size;
if best_size == 0 {
break; }
}
c = self.nodes[c].right;
}
best
};
if self.cols[col].size == 0 {
return;
}
self.cover(col);
let mut row_node = self.nodes[col].down;
while row_node != col {
self.solution_stack.push(row_node);
let mut right_node = self.nodes[row_node].right;
while right_node != row_node {
self.cover(self.nodes[right_node].column);
right_node = self.nodes[right_node].right;
}
self.search(solutions);
let mut left_node = self.nodes[row_node].left;
while left_node != row_node {
self.uncover(self.nodes[left_node].column);
left_node = self.nodes[left_node].left;
}
self.solution_stack.pop();
row_node = self.nodes[row_node].down;
}
self.uncover(col);
}
fn cover(&mut self, col: usize) {
let left_col = self.nodes[col].left;
let right_col = self.nodes[col].right;
self.nodes[left_col].right = right_col;
self.nodes[right_col].left = left_col;
let mut row_node = self.nodes[col].down;
while row_node != col {
let mut node = self.nodes[row_node].right;
while node != row_node {
let up = self.nodes[node].up;
let down = self.nodes[node].down;
self.nodes[up].down = down;
self.nodes[down].up = up;
self.cols[self.nodes[node].column].size -= 1;
node = self.nodes[node].right;
}
row_node = self.nodes[row_node].down;
}
}
fn uncover(&mut self, col: usize) {
let mut row_node = self.nodes[col].up;
while row_node != col {
let mut node = self.nodes[row_node].left;
while node != row_node {
let up = self.nodes[node].up;
let down = self.nodes[node].down;
self.nodes[up].down = node;
self.nodes[down].up = node;
self.cols[self.nodes[node].column].size += 1;
node = self.nodes[node].left;
}
row_node = self.nodes[row_node].up;
}
let left_col = self.nodes[col].left;
let right_col = self.nodes[col].right;
self.nodes[left_col].right = col;
self.nodes[right_col].left = col;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_small_exact_cover() {
let matrix = vec![
vec![true, false, true, false],
vec![true, false, false, true],
vec![false, true, true, false],
vec![false, true, false, true],
vec![true, false, true, false],
vec![false, true, false, true],
];
let mut dlx = DancingLinks::new(&matrix);
let solutions = dlx.solve_all();
assert!(!solutions.is_empty());
for sol in solutions {
let mut covered = vec![false; 4];
for r in sol {
for (c, &val) in matrix[r].iter().enumerate() {
if val {
assert!(!covered[c], "Column {} covered twice", c);
covered[c] = true;
}
}
}
assert!(covered.iter().all(|&x| x), "Not all columns covered");
}
}
#[test]
fn test_empty() {
let matrix: Vec<Vec<bool>> = vec![];
let mut dlx = DancingLinks::new(&matrix);
let solutions = dlx.solve_all();
assert_eq!(solutions.len(), 1);
assert!(solutions[0].is_empty());
}
#[test]
fn test_single_col() {
let matrix = vec![vec![true], vec![false]];
let mut dlx = DancingLinks::new(&matrix);
let solutions = dlx.solve_all();
assert_eq!(solutions, vec![vec![0]]);
}
}