回溯8皇后Python问题

回溯8皇后Python问题,python,algorithm,backtracking,python-chess,Python,Algorithm,Backtracking,Python Chess,我已经开始用Python中的回溯来解决8皇后问题。一切都很好。它甚至打印出了第一个答案。然而,它在第一次回溯尝试中陷入困境 任务听起来是这样的: 实现一个解决8皇后难题的Python函数。8皇后拼图是把8个皇后放在一个棋盘上,这样,任何一个皇后都不能捕获其他皇后。请注意,皇后可以在任何方向上正交或对角移动 您应该实现一个函数solve(),调用该函数时,它将打印谜题的第一个解决方案,然后等待输入。用户按下“回车”键后,将打印下一个解决方案,依此类推 -您的程序应该能够找到谜题的所有解决方案,并且

我已经开始用Python中的回溯来解决8皇后问题。一切都很好。它甚至打印出了第一个答案。然而,它在第一次回溯尝试中陷入困境

任务听起来是这样的:

实现一个解决8皇后难题的Python函数。8皇后拼图是把8个皇后放在一个棋盘上,这样,任何一个皇后都不能捕获其他皇后。请注意,皇后可以在任何方向上正交或对角移动

您应该实现一个函数solve(),调用该函数时,它将打印谜题的第一个解决方案,然后等待输入。用户按下“回车”键后,将打印下一个解决方案,依此类推

-您的程序应该能够找到谜题的所有解决方案,并且每个解决方案只能找到一次。”

-它应该很容易修改您的程序,因此,它适用于不同的电路板尺寸。提示:

-在任何一排中,都只有一位女王。因此,您只需要计算8个皇后中的每一个可以放置在其中的列

-您应该实现一个递归函数solve(n),该函数为n+1皇后找到一个位置,然后为n+1皇后递归调用自己(除非所有皇后都已放置)。它应该系统地探索使用回溯的所有可能性

-如有必要,我们允许(并鼓励)定义额外的函数(solve()除外),以提高代码质量


这是一个如何递归解决8皇后问题的示例,使用一个简单的列表来表示电路板。像[8,4,1,3,6,2,7,5]这样的列表从上到下表示棋盘的8行,第一行的第8列有一个Q,第7行的第4列,第6行的第1列。。。最后一行的第五列

一个解决方案是从一个空板开始构建的
[]
,方法是将一个Q放置在下一行的一个列位置,在该列位置无法获取它。可能的位置是之前未采用的列(这是函数
solve
中的for循环)。对于每个可能的列位置,函数
issafe
检查该位置是否安全,不会被板上已有的Qs对角占据。如果位置是安全的,则解决方案板将延长另一行,并且解决方案将递归,直到填充板(
len(board)==boardsize
),此时解决方案计数将增加,并显示板

请注意,函数
solve
适用于任何大小的方格棋盘-所需大小作为参数传递给
solve
,函数返回找到的解的总数

希望这有助于解释如何在不使用
numpy
的情况下递归解决8皇后问题

def display(solution_number, board):
    row = '|   ' * len(board) + '|'
    hr  = '+---' * len(board) + '+'
    for col in board:
        print(hr)
        print(row[:col*4-3],'Q',row[col*4:])
    print(f'{hr}\n{board}\nSolution - {solution_number}\n')

def issafe(q, board, x=1):
    if not board: return True
    if board[-1] in [q+x,q-x]: return False
    return issafe(q, board[:-1], x+1)

def solve(boardsize, board=[], solutions_found=0):
    if len(board) == boardsize:
        solutions_found += 1
        display(solutions_found, board)
    else:
        for q in [col for col in range(1,boardsize+1) if col not in board]:
            if issafe(q,board):
                solutions_found = solve(boardsize, board + [q], solutions_found)
    return solutions_found

if __name__ == '__main__':
    solutions = solve(8)
    print(f'{solutions} solutions found')
您提到使用
yield
-这也是可能的,它将
solve
转换为生成器,一次生成一个解决方案。然后,您的程序可以使用
for
循环依次接收每个解决方案,并根据需要对其进行处理。以下
yield
解决方案适用于Python v.3.3以后的版本,因为它使用了
yield from

def display(solution_number, board):
    row = '|   ' * len(board) + '|'
    hr  = '+---' * len(board) + '+'
    for col in board:
        print(hr)
        print(row[:col*4-3],'Q',row[col*4:])
    print(f'{hr}\n{board}\nSolution - {solution_number}\n')

def issafe(q, board, x=1):
    if not board: return True
    if board[-1] in [q+x,q-x]: return False
    return issafe(q, board[:-1], x+1)

def solve(boardsize, board=[]):
    if len(board) == boardsize:
        yield board
    else:
        for q in [col for col in range(1,boardsize+1) if col not in board]:
            if issafe(q,board):
                yield from solve(boardsize, board + [q])

if __name__ == '__main__':
    for solutionnumber, solution in enumerate(solve(8)):
        display(solutionnumber+1, solution)
如果递归函数
issafe
令人困惑,这里是一个非递归版本:

def issafe(q, board):
    x = len(board)
    for col in board:
        if col in [q+x,q-x]: return False
        x -= 1
    return True

为什么要使用
numpy
来实现此目的?这不是一项任务要求,一个电路板配置最好表示为一个8行的列表,每列一个。例如,
grid=[1,3,6,4,2,7,5,8]
表示在第1列的第1行、第2列的第3行、第3列的第6行、第4列的第4行中有一个Q的电路板。Hello@mkam!现在我完全摆脱了递归。也许yield就可以了?我仍然不明白为什么需要
numpy
,或者为什么需要摆脱递归。对于这个问题,递归解决方案是很自然的。我将发布一个示例解决方案作为答案,这样您就可以看到如何使用一个简单的1-d列表来表示一块板递归地执行此操作。我已经将您的代码与我的代码合并,并且它可以正常工作。然而,我仍然不太明白issafe函数是如何工作的。如果“对角线”是自由的,我可能会通过检查每个可能的维度对其进行迭代编程,请您向我解释一下好吗?
issafe
获取一个部分完成的电路板,例如[8,4,1],以及下一行中可能的位置q,例如6。它回答了这样一个问题:“如果在第1、2和3行的第8、4和1列中有皇后,那么在第4行的第6列中放置皇后是否安全?”?它只需要对角检查,因为
solve
只选择尚未使用的可能列位置。因此,它沿对角线向后检查列表,查看列表中的最后一项是q-1还是q+1,然后前一项是q-2或q+2,然后前一项是q-3或q+3。希望有帮助。
import numpy as np

    from numpy.core._multiarray_umath import ndarray
    
    
    def print_grid(solutions_found, board) -> None:
        line: ndarray
        len_board = len(board)
        grid: ndarray = np.zeros((len_board, len_board), dtype=int)
        for i, number in enumerate(board):
            grid[i - 1][number - 1] = 1
        for line in grid:
            for square in line:
                if square == 0:
                    print(".", end=" ")
                else:
                    print("Q", end=" ")
            print()
        print(f'Solution - {solutions_found}')
    
    
    def solve(boardsize, board=[], solutions_found=0):
        if len(board) == boardsize:
            solutions_found += 1
            print_grid(solutions_found, board)
        else:
            for q in [col for col in range(1, boardsize + 1) if col not in board]:
                if is_safe(q, board):
                    solutions_found = solve(boardsize, board + [q], solutions_found)
        return solutions_found
    
    
    def is_safe(q, board, x=1):
        if not board:
            return True
        if board[-1] in [q + x, q - x]:
            return False
        return is_safe(q, board[:-1], x + 1)
    
    
    if __name__ == '__main__':
        solve(8)
def display(solution_number, board):
    row = '|   ' * len(board) + '|'
    hr  = '+---' * len(board) + '+'
    for col in board:
        print(hr)
        print(row[:col*4-3],'Q',row[col*4:])
    print(f'{hr}\n{board}\nSolution - {solution_number}\n')

def issafe(q, board, x=1):
    if not board: return True
    if board[-1] in [q+x,q-x]: return False
    return issafe(q, board[:-1], x+1)

def solve(boardsize, board=[], solutions_found=0):
    if len(board) == boardsize:
        solutions_found += 1
        display(solutions_found, board)
    else:
        for q in [col for col in range(1,boardsize+1) if col not in board]:
            if issafe(q,board):
                solutions_found = solve(boardsize, board + [q], solutions_found)
    return solutions_found

if __name__ == '__main__':
    solutions = solve(8)
    print(f'{solutions} solutions found')
def display(solution_number, board):
    row = '|   ' * len(board) + '|'
    hr  = '+---' * len(board) + '+'
    for col in board:
        print(hr)
        print(row[:col*4-3],'Q',row[col*4:])
    print(f'{hr}\n{board}\nSolution - {solution_number}\n')

def issafe(q, board, x=1):
    if not board: return True
    if board[-1] in [q+x,q-x]: return False
    return issafe(q, board[:-1], x+1)

def solve(boardsize, board=[]):
    if len(board) == boardsize:
        yield board
    else:
        for q in [col for col in range(1,boardsize+1) if col not in board]:
            if issafe(q,board):
                yield from solve(boardsize, board + [q])

if __name__ == '__main__':
    for solutionnumber, solution in enumerate(solve(8)):
        display(solutionnumber+1, solution)
def issafe(q, board):
    x = len(board)
    for col in board:
        if col in [q+x,q-x]: return False
        x -= 1
    return True