[英]z3: solve the Eight Queens puzzle
我正在使用Z3解决八皇后拼图。 我知道在这个问题上每个女王可以用一个整数表示。 但是,当我用两个整数代表一个女王时如下:
from z3 import *
X = [[Int("x_%s_%s" % (i+1, j+1)) for j in range(8)] for i in range(8) ]
cells_c = [Or(X[i][j] == 0, X[i][j] == 1) for i in range(8) for j in range(8) ]
rows_c = [Sum(X[i]) == 1 for i in range(8)]
cols_c = [Sum([X[i][j] for i in range(8)]) == 1 for j in range(8) ]
diagonals_c = [Implies(And(X[i][j] == 1, X[k][h] == 1), abs(k - i) != abs(j - h))
for i in range(8) for j in range(8)
for k in range(8) for h in range(8)]
eight_queens_c = cells_c + rows_c + cols_c + diagonals_c
s = Solver()
s.add(eight_queens_c)
if s.check() == sat:
m = s.model()
r = [[m.evaluate(X[i][j]) for j in range(8)] for i in range(8)]
print_matrix(r)
else:
print "failed to solve"
它返回:
failed to solve
代码有什么问题?
谢谢!
由于以下代码,您的问题过度约束 :
diagonals_c = [Implies(And(X[i][j] == 1, X[k][h] == 1), abs(k - i) != abs(j - h))
for i in range(8) for j in range(8)
for k in range(8) for h in range(8)]
每当对i, j
等于k, h
abs(k - i) = 0 = abs(j - h)
并且暗示结论是False
。
只有当它的前提是False
时候才会满足对False
结论的含义。 在你的问题的表述中,只有当对i, j
等于k, h
时, X[i][j] == 1
和X[k][h] == 1
的情况绝不是这样的情况才有可能也就是说,如果对于任何i, j
, X[i][j] = 1
的情况永远不会发生。 但是后一规则违反了行和列基数约束,这些约束要求对于每个列 / 行存在至少一个单元X_i_j
st X_i_j = 1
。 因此,该公式是不unsat
。
为了解决这个问题,最小的修复是简单地排除X[i][j]
和X[k][h]
指向同一个单元格的情况:
diagonals_c = [Implies(And(X[i][j] == 1, X[k][h] == 1,
i != k, j != h), abs(k - i) != abs(j - h))
for i in range(8) for j in range(8)
for k in range(8) for h in range(8)]
在此更改后,找到解决方案。
例如
~$ python queens.py
[[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0]]
注意:在你的diagonals_c
编码中,你为每个单元格引入了n*n
约束,你的问题中有n*n
单元格。 此外,由于索引空间中的对称性,每个约束生成“完全相同”两次。 但是,每个单元格与少于2*n
其他单元格冲突(有些冲突少于n
),因此引入如此多的条款看起来有点过分,这些条款不会在搜索中提供任何有用的贡献,除了放慢速度 也许更可扩展的方法是使用基数约束(即Sum
),不仅用于行和列 ,还用于对角线 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.