我正在使用python-constraint库try 解决n-queens problem (n个女王被放置在n乘n的板上,并且它们的排列方式必须使它们不会互相威胁)

我的公式是这样的:

from constraint import *

n = 8
problem = Problem()
problem.addVariables(range(n),range(n))

for i in range(n):
  for j in range(i):
    problem.addConstraint(lambda a,b:a!=b,(i,j))
    problem.addConstraint(lambda a,b:abs(a-b)!=abs(i-j),(i,j))

然而,当我试图用problem.getSolution()得到解决方案时,我只得到None.我做错了什么?

推荐答案

生成的Lambda的非常classic 的错误(与约束无关).

考虑这个代码

ll=[]
for i in range(3):
    l=lambda: print("i=", i)
    ll.append(l)

ll[0]()
ll[1]()
ll[2]()

它不会像您期望的那样显示0、1、2. 它显示2、2、2.

这3个(不同的)函数都做同样的事情:它们显示i值.但如果ll[0]ll[1]ll[2]确实是3个不同的功能,那么仍然只有一个i.当然,当你创建ll[0]时,i值是0.但ll[0]作业(job)是为了显示i,而不是显示i曾经在创建ll[0]时所具有的值.

有多种方法可以强制判断i

它们能互相

ll=[]
for i in range(3):
   (lambda i: ll.append(lambda: print("i=", i)))(i)
ll[0]()
ll[1]()
ll[2]()

此时显示为0、1、2. 因为ll[0]就是显示i.但这次i不是for循环的(唯一)计数器.i是所调用的拉姆达的参数.而且它们的数量与调用该Lambda(lambda i:...函数,而不是在其中创建的函数)的数量一样多.

同一代码的更清晰(但更长)版本将是

ll=[]

def createAndAddLambdaToLL(x):
    l=lambda: print("x=", x)
    ll.append(l)

for i in range(3):
    createAndAddLambdaToLL(i)

ll[0]()
ll[1]()
ll[2]()

createAndAddLambdaToLL是我之前代码的外部Lambda. 请注意,我还重命名了参数x,以明确打印的不是i(i,在ll[?]()次调用时,所有这些都是2),而是打印的是x.还有3个不同的x,当调用createAndAddLambdaToLL时创建.

编辑:我添加了Bakuriu的 comments ;另一种方法确实是添加可选参数:

ll=[]
for i in range(3):
    l=lambda i=i: print("i=", i)
    ll.append(l)
ll[0]()
ll[1]()
ll[2]()

确实打印0,1,2

因为这里有2种i种.打印的i不是for循环计数器.它是局部参数i(ll[0](12)打印12).这样的i有3个(1个,每个ll[...]个本地). 默认值是创建函数时计数器i的值.

因此,当谈到理解为什么它是必要的以及为什么它有效时,Bakuriu的解决方案和我的一样复杂.但写作要简单得多,而且几乎自然.

回到你的问题

from constraint import *

n = 8
problem = Problem()
problem.addVariables(range(n),range(n))

def addConstraintDiag(i,j):
    problem.addConstraint(lambda a,b: abs(a-b)!=abs(i-j), (i,j))

for i in range(n):
    for j in range(i):
        problem.addConstraint(lambda a,b:a!=b,(i,j))
        addConstraintDiag(i,j)

print(problem.getSolutions())

请注意,第一个约束(不共享行)不是问题,因为lambda a,b:a!=b不依赖于ij(事实上,它是同一函数的28倍.您可以在循环外为所有人创建一次它,并将其作为约束添加28次.但重点是,这并不重要.该功能不需要其ij是全部28个组合,因为它甚至不使用ij.约束本身可以,但Lambda则不然.

不过,为了安全起见,您可以在函数addConstraints中添加2个约束,而不必认真思考是否需要对ij进行部分判断.

编辑: 或者,使用Bakuriu的命令:

from constraint import *

n = 8
problem = Problem()
problem.addVariables(range(n),range(n))

for i in range(n):
    for j in range(i):
        problem.addConstraint(lambda a,b:a!=b,(i,j))
        problem.addConstraint(lambda a,b,i=i,j=j: abs(a-b)!=abs(i-j), (i,j))
print(problem.getSolutions())

Python相关问答推荐

如果条件为真,则Groupby.mean()

点到面的Y距离

如何将双框框列中的成对变成两个新列

Python上的Instagram API:缺少client_id参数"

如何标记Spacy中不包含特定符号的单词?

使用索引列表列表对列进行切片并获取行方向的向量长度

部分视图的DataFrame

在单个对象中解析多个Python数据帧

Django—cte给出:QuerySet对象没有属性with_cte''''

如何指定列数据类型

Python Tkinter为特定样式调整所有ttkbootstrap或ttk Button填充的大小,适用于所有主题

pandas:对多级列框架的列进行排序/重新排序

如何在BeautifulSoup/CSS Select 器中处理regex?

替换现有列名中的字符,而不创建新列

python sklearn ValueError:使用序列设置数组元素

如何根据rame中的列值分别分组值

提取最内层嵌套链接

一维不匹配两个数组上的广义ufunc

如何在Pandas中用迭代器求一个序列的平均值?

对当前的鼹鼠进行编码,并且我的按键获得了注册