Google or-tools的样例之一是用于n皇后问题的求解器。底部指出,通过向约束求解器添加对称性破坏约束可以改善实现。
我在互联网上搜索到了关于N皇后问题对称性破缺的限制条件,但我无法想象如何将这些限制条件转换为实现它们的Python代码。
编辑:这是一个不好的问题,让我们更新...
我尝试了什么?
这是来自上面第一个链接的设置:
from ortools.constraint_solver import pywrapcp
N = 8
solver = pywrapcp.Solver("n-queens")
# Creates the variables.
# The array index is the column, and the value is the row.
queens = [solver.IntVar(0, N - 1, "x%i" % i) for i in range(N)]
# Creates the constraints.
# All rows must be different.
solver.Add(solver.AllDifferent(queens))
# All columns must be different because the indices of queens are all different.
# No two queens can be on the same diagonal.
solver.Add(solver.AllDifferent([queens[i] + i for i in range(N)]))
solver.Add(solver.AllDifferent([queens[i] - i for i in range(N)]))
# TODO: add symmetry breaking constraints
db = solver.Phase(queens, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)
solver.NewSearch(db)
num_solutions = 0
while solver.NextSolution():
num_solutions += 1
solver.EndSearch()
print()
print("Solutions found:", num_solutions)
print("Time:", solver.WallTime(), "ms")
我知道我可以成功地实现简单的约束。如果我想要确保解决方案总是在第一行的第一列有一个皇后,我可以像这样实现:
solver.Add(queens[0] == 0)
queens[0]
变量表示皇后在第一列的位置,只有当第一列的第一行有一个皇后时,才满足此约束条件。当然,这并不是我想要做的,因为可能存在解决方案不包括任何角落单元格。
n-皇后问题的对称性破坏约束如下所示。它们直接从第二段中的链接中提取。
我了解这些约束条件的工作原理。想法是,您可以将此函数应用于n皇后棋盘上的每个单元格,以将状态转换为等效状态。其中一个状态将是该状态的规范表示。这被用作通过消除重复评估来修剪未来处理的方法。如果我只是事后实现它,我会按照上述描述的方式进行,使用每个可能的对称性破坏函数转换状态,计算某种状态哈希(例如,每列中选定行的字符串),并选择每个提议解决方案的最低解决方案。跳过我们以前见过的未来处理。
我的问题是,我不知道如何将这些转换转换为google or-tools约束编程求解器的约束条件。
让我们看看最简单的一个,d1(r [i] = j)=> r [j] = i,即关于主对角线的反射。我知道需要将变换应用于所有单元格,然后与当前状态进行比较,以防止其被扩展。我不了解足够的Python知识来了解在此处适用于变换的表达式类型,而且我无法弄清楚如何创建用于此特定求解器的约束,以将变换与当前状态进行比较。
state = [queens[i].Value() for i in range(N)]
symX = [state[N - (i + 1)] for i in range(N)]
symY = [N - (state[i] + 1) for i in range(N)]
symD1 = [state.index(i) for i in range(N)]
symD2 = [N - (state.index(N-(i+1)) + 1) for i in range(N)]
symR90 = [N - (state.index(i) + 1) for i in range(N)]
symR180 = [N - (state[N-(i+1)] + 1) for i in range(N)]
symR270 = [state.index(N-(i+1)) for i in range(N)]