在棋盘上8皇后| PYTHON |内存错误

时间:2017-09-04 16:56:07

标签: python chess

我遇到了这个问题,应该在棋盘上放置8个女王,这样就没有人可以互相残杀。这就是我试图解决的问题:

import itertools
def allAlive(position):
    qPosition=[]
    for i in range(8):
        qPosition.append(position[2*i:(2*i)+2])
    hDel=list(qPosition)     #Horizontal
    for i in range(8): 
        a=hDel[0]
        del hDel[0]
        l=len(hDel)
        for j in range(l):
            if a[:1]==hDel[j][:1]:
                return False
    vDel=list(qPosition)     #Vertical
    for i in range(8):
        a=vDel[0]
        l=len(vDel)
        for j in range(l):
            if a[1:2]==vDel[j][1:2]:
                return False
    cDel=list(qPosition)     #Cross
    for i in range(8):
        a=cDel[0]
        l=len(cDel)
        for j in range(l):
            if abs(ord(a[:1])-ord(cDel[j][:1]))==1 and abs(int(a[1:2])-int(cDel[j][1:2]))==1:
                return False
    return True
chessPositions=['A1','A2','A3','A4','A5','A6','A7','A8','B1','B2','B3','B4','B5','B6','B7','B8','C1','C2','C3','C4','C5','C6','C7','C8','D1','D2','D3','D4','D5','D6','D7','D8','E1','E2','E3','E4','E5','E6','E7','E8','F1','F2','F3','F4','F5','F6','F7','F8','G1','G2','G3','G4','G5','G6','G7','G8','H1','H2','H3','H4','H5','H6','H7','H8']
qPositions=[''.join(p) for p in itertools.combinations(chessPositions,8)]
for i in qPositions:
    if allAlive(i)==True:
        print(i)
  

追踪(最近一次呼叫最后一次):

     

qPositions = [''。在itertools.combinations(chessPositions,8)中为p加入(p)]

     

的MemoryError

我还是个新手。我怎么能克服这个错误呢?还是有更好的方法来解决这个问题?

3 个答案:

答案 0 :(得分:4)

你要做的事情是不可能的;)!

qPositions=[''.join(p) for p in itertools.combinations(chessPositions,8)]

表示您将获得一个长度为64 choose 8 = 4426165368的列表,因为len(chessPositions) = 64,您无法存储在内存中。为什么不?结合我在评论中提到的内容和@augray的回答,上述操作的结果将是一个列表,

(64 choose 8) * 2 * 8 bytes ~ 66GB
RAM的

,因为它将有64 choose 8个元素,每个元素将有8个子串,如'A1',每个子串都包含2个字符。一个字符需要1个字节。

你必须找到另一种方式。我没有回答,因为这是你的工作。 n-queens 问题属于动态编程。我建议你google'n queens problem python'并搜索答案。然后尝试理解代码和动态编程。

我确实在搜索你,看看this video。正如@JeanFrançois-Fabre所建议的那样,回溯。你的工作现在是观看视频一次,两次......只要你不理解问题的解决方案。然后打开你喜欢的编辑器(我的是Vi:D)并编码下来!

答案 1 :(得分:4)

这是一个理解"科学" (或者更准确地说,数学)计算机科学的一部分,同样重要的是理解编程的细节。

documentation for itertools.combinations,我们看到返回的项目数为n! / r! / (n-r)!,其中n是输入集合的长度(在您的情况下,国际象棋位置的数量为64)并且r是您想要返回的子序列的长度(在您的情况下为8)。正如@campovski指出的那样,这导致4,426,165,368。每个返回的子序列将包含8 * 2个字符,每个字符都是一个字节(更不用说保存这些字符并计算答案的其他数据结构的开销)。每个字符都是1个字节,因此总的来说,只计算结果子序列的内存消耗量4,426,165,368*2*8=70818645888。除以1024 ^ 3得到这些子序列所占的内存Gigs数量,约为66GB。

我假设你没有那么多记忆:-)。计算这个问题的答案需要一个经过深思熟虑的算法,而不仅仅是"蛮力"。我建议对这个问题进行一些研究 - Wikipedia看起来是个好地方。

答案 2 :(得分:1)

正如其他答案所说,你不能让每一个组合都适合记忆,你不应该使用蛮力,因为速度会很慢。但是,如果你想使用蛮力,你可以约束问题,并消除常见的行和列并检查对角线

from itertools import permutations
#All possible letters
letters = ['a','b','c','d','e','f','g','h']

#All possible numbers
numbers = [str(i) for i in range(1,len(letters)+1)]

#All possible permutations given rows != to eachother and columns != to eachother
r = [zip(letters, p) for p in permutations(numbers,8)]

#Formatted for your function
points = [''.join([''.join(z) for z in b]) for b in r]

另外作为一个注释,这行代码试图首先找到所有组合,然后提供你的函数,这是浪费内存。

qPositions=[''.join(p) for p in itertools.combinations(chessPositions,8)]

如果您确定要使用蛮力方法,则可以。只需修改itertools combinations的代码即可。移除yieldreturn,然后一次只提供一个检查功能。