Google or-tools 的示例之一是 n-queens 问题的求解器。 在底部,它说可以通过向约束求解器添加对称破坏约束来改进实现。
环顾互联网,我发现了 n-queens 问题的对称破坏约束,但我一生都无法弄清楚如何将这些约束转换为实现它们的 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-queens 问题的对称破缺约束如下所示。它们是直接从第二段中的链接中提取的。
我了解这些约束是如何工作的。这个想法是,您可以将此函数应用于 n-queens 板上的每个单元格,以便将状态转换为等效状态。这些状态之一将是该状态的规范表示。这被用作通过消除重复评估来修剪未来处理的方法。
如果我只是以事后的方式实现这一点,我会完全按照我上面描述的那样做,使用每个可能的对称破坏函数转换状态,计算某种状态散列(例如,每列中选定行的字符串)并为每个建议的解决方案选择最低的一个。跳过我们以前见过的未来处理。
我的问题是我不知道如何将这些转换转换为 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)]