z3:解决八皇后难题 [英] z3: solve the Eight Queens puzzle

查看:31
本文介绍了z3:解决八皇后难题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Z3 来解决八皇后难题.我知道在这个问题中每个皇后都可以用一个整数表示.但是,当我用两个整数表示一个女王时,如下所示:

I'm using Z3 to solve the Eight Queens puzzle. I know that each queen can be represented by a single integer in this problem. But, when I represent a queen by two integers as following:

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

代码有什么问题?

谢谢!

推荐答案

由于以下代码段,您的问题过度约束:

You problem is over-constrained due to the following piece of code:

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 时,则

Whenever the pair i, j is equal to k, h then

 abs(k - i) = 0 = abs(j - h)

且蕴涵结论为False.

具有False 结论的蕴涵只有在其前提也是False 时才得到满足.在你对问题的表述中,这只有在 X[i][j] == 1X[k][h] == 1 每当 i, j 等于 k, h 时,也就是说,如果 X[i][j] =1 对于任何 i, j.但是后一条规则违反了 rowscolumns 基数约束,这要求对于每个 column/row 存在于至少一个单元格 X_i_j stX_i_j = 1.因此,公式是unsat.

An implication with a False conclusion is satisfied only when its premise is False too. In your formulation of the problem, this is only possible if it is never the case that X[i][j] == 1 and X[k][h] == 1 whenever the pair i, j is equal k, h, that is, if it is never the case that X[i][j] = 1 for any i, j. But the latter rule violates the rows and columns cardinality constraints which require that for each column/row there exists at lest one cell X_i_j s.t. X_i_j = 1. Thus, the formula is unsat.

为了解决这个问题,一个最小的解决方法是简单地排除 X[i][j]X[k][h] 引用同一个单元格:

To solve this, a minimal fix is to simply exclude the case in which X[i][j] and X[k][h] refer to the same cell:

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)]

经过这次改动后,找到了解决方案.

After this change, a solution is found.

例如

~$ 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).


NOTE: in your encoding of diagonals_c, you introduce n*n constraints for each cell, and there are n*n cells in your problem. In addition, due to symmetries in the index space, each constraint is generated 'exactly the same' twice. However, each cell conflicts with fewer than 2*n other cells (some conflict with fewer than n), so it looks like a bit of an overkill to introduce so many clauses that don't provide any useful contribution along the search, except that of slowing it down. Perhaps a more scalable approach would be that of employing cardinality constraints (i.e. Sum) not only for rows and columns but also for diagonals.

这篇关于z3:解决八皇后难题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆