Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/combinat/matrices/dlxcpp.py
4040 views
1
"""
2
Dancing links C++ wrapper
3
"""
4
#*****************************************************************************
5
# Copyright (C) 2008 Carlo Hamalainen <[email protected]>,
6
#
7
# Distributed under the terms of the GNU General Public License (GPL)
8
#
9
# This code is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
# General Public License for more details.
13
#
14
# The full text of the GPL is available at:
15
#
16
# http://www.gnu.org/licenses/
17
#*****************************************************************************
18
19
# OneExactCover and AllExactCovers are almost exact copies of the
20
# functions with the same name in sage/combinat/dlx.py by Tom Boothby.
21
22
from dancing_links import dlx_solver
23
24
def DLXCPP(rows):
25
"""
26
Solves the Exact Cover problem by using the Dancing Links algorithm
27
described by Knuth.
28
29
Consider a matrix M with entries of 0 and 1, and compute a subset
30
of the rows of this matrix which sum to the vector of all 1's.
31
32
The dancing links algorithm works particularly well for sparse
33
matrices, so the input is a list of lists of the form::
34
35
[
36
[i_11,i_12,...,i_1r]
37
...
38
[i_m1,i_m2,...,i_ms]
39
]
40
41
where M[j][i_jk] = 1.
42
43
The first example below corresponds to the matrix::
44
45
1110
46
1010
47
0100
48
0001
49
50
which is exactly covered by::
51
52
1110
53
0001
54
55
and
56
57
::
58
59
1010
60
0100
61
0001
62
63
If soln is a solution given by DLXCPP(rows) then
64
65
[ rows[soln[0]], rows[soln[1]], ... rows[soln[len(soln)-1]] ]
66
67
is an exact cover.
68
69
Solutions are given as a list
70
71
EXAMPLES::
72
73
sage: rows = [[0,1,2]]
74
sage: rows+= [[0,2]]
75
sage: rows+= [[1]]
76
sage: rows+= [[3]]
77
sage: print [ x for x in DLXCPP(rows) ]
78
[[3, 0], [3, 1, 2]]
79
"""
80
81
if len(rows) == 0: return
82
83
x = dlx_solver(rows)
84
85
while x.search():
86
yield x.get_solution()
87
88
def AllExactCovers(M):
89
"""
90
Solves the exact cover problem on the matrix M (treated as a dense
91
binary matrix).
92
93
EXAMPLES: No exact covers::
94
95
sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]])
96
sage: print [cover for cover in AllExactCovers(M)]
97
[]
98
99
Two exact covers::
100
101
sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]])
102
sage: print [cover for cover in AllExactCovers(M)]
103
[[(1, 1, 0), (0, 0, 1)], [(1, 0, 1), (0, 1, 0)]]
104
"""
105
rows = []
106
for R in M.rows():
107
row = []
108
for i in range(len(R)):
109
if R[i]:
110
row.append(i)
111
rows.append(row)
112
for s in DLXCPP(rows):
113
yield [M.row(i) for i in s]
114
115
def OneExactCover(M):
116
"""
117
Solves the exact cover problem on the matrix M (treated as a dense
118
binary matrix).
119
120
EXAMPLES::
121
122
sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) #no exact covers
123
sage: print OneExactCover(M)
124
None
125
sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) #two exact covers
126
sage: print OneExactCover(M)
127
[(1, 1, 0), (0, 0, 1)]
128
"""
129
130
for s in AllExactCovers(M):
131
return s
132
133
134
135