Skip to content

Commit bd7226f

Browse files
committed
Style: autoformat dancing_links.py to pass pre-commit checks
1 parent a71618f commit bd7226f

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

other/dancing_links.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"""
2+
Dancing Links (DLX) Algorithm for Exact Cover Problem
3+
4+
Author: fab-c14
5+
Reference: Donald Knuth, "Dancing Links" (Algorithm X)
6+
7+
DLX is an efficient algorithm for solving the Exact Cover problem, such as
8+
tiling, polyomino puzzles, or Sudoku.
9+
10+
This implementation demonstrates DLX for a small exact cover problem.
11+
12+
Usage Example:
13+
>>> universe = [1, 2, 3, 4, 5, 6, 7]
14+
>>> subsets = [
15+
... [1, 4, 7],
16+
... [1, 4],
17+
... [4, 5, 7],
18+
... [3, 5, 6],
19+
... [2, 3, 6, 7],
20+
... [2, 7]
21+
... ]
22+
>>> for solution in dlx(universe, subsets):
23+
... print(solution)
24+
[0, 3, 4]
25+
[1, 2, 5]
26+
"""
27+
28+
from collections.abc import Iterator
29+
30+
31+
def dlx(universe: list[int], subsets: list[list[int]]) -> Iterator[list[int]]:
32+
"""Yields solutions to the Exact Cover problem using Algorithm X (Dancing Links)."""
33+
cover: dict[int, set[int]] = {u: set() for u in universe}
34+
for idx, subset in enumerate(subsets):
35+
for elem in subset:
36+
cover[elem].add(idx)
37+
partial: list[int] = []
38+
39+
def search() -> Iterator[list[int]]:
40+
if not cover:
41+
yield list(partial)
42+
return
43+
# Choose column with fewest rows (heuristic)
44+
c = min(cover, key=lambda col: len(cover[col]))
45+
for r in list(cover[c]):
46+
partial.append(r)
47+
removed: dict[int, set[int]] = {}
48+
for j in subsets[r]:
49+
for i in cover[j].copy():
50+
for k in subsets[i]:
51+
if k == j:
52+
continue
53+
if k in cover:
54+
cover[k].discard(i)
55+
removed[j] = cover.pop(j)
56+
yield from search()
57+
# Backtrack
58+
for j, s in removed.items():
59+
cover[j] = s
60+
for i in cover[j]:
61+
for k in subsets[i]:
62+
if k != j and k in cover:
63+
cover[k].add(i)
64+
partial.pop()
65+
66+
yield from search()
67+
68+
69+
if __name__ == "__main__":
70+
# Example: Solve the cover problem from Knuth's original paper
71+
universe = [1, 2, 3, 4, 5, 6, 7]
72+
subsets = [
73+
[1, 4, 7],
74+
[1, 4],
75+
[4, 5, 7],
76+
[3, 5, 6],
77+
[2, 3, 6, 7],
78+
[2, 7],
79+
]
80+
for solution in dlx(universe, subsets):
81+
print("Solution:", solution)

0 commit comments

Comments
 (0)