简体   繁体   English

所有可能的N-皇后

[英]All possible N-Queens

The classic N-Queens problem finds a way to place n queens on an n×n chessboard such that no two queens attack each other. 经典的N皇后问题找到了一种方法,可以将n个皇后放置在n×n棋盘上,这样就不会有两个皇后互相攻击。 This is my solution to the N-Queens problem. 这是我对N皇后问题的解决方案。

class Solution(object):
    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """
        grid = [['.' for _ in range(n)] for _ in range(n)]
        solved = self.helper(n, 0, grid)
        if solved:
            return ["".join(item) for item in grid]
        else:
            return None

    def helper(self, n, row, grid):
        if n == row:
            return True
        for col in range(n):
            if self.is_safe(row, col, grid):
                grid[row][col] = 'Q'
                if self.helper(n, row + 1, grid):
                    return True
                else:
                    grid[row][col] = '.'
        return False

    def is_safe(self, row, col, board):
        for i in range(len(board)):
            if board[row][i] == 'Q' or board[i][col] == 'Q':
                return False
        i = 0
        while row - i >= 0 and col - i >= 0:
            if board[row - i][col - i] == 'Q':
                return False
            i += 1
        i = 0
        while row + i < len(board) and col + i < len(board):
            if board[row + i][col - i] == 'Q':
                return False
            i += 1
        i = 1
        while row + i < len(board) and col - i >= 0:
            if board[row + i][col - i] == 'Q':
                return False
            i += 1
        i = 1
        while row - i >= 0 and col + i < len(board):
            if board[row - i][col + i] == 'Q':
                return False
            i += 1
        return True


if __name__ == '__main__':
    solution = Solution()
    print(solution.solveNQueens(8))

An extension to this problems states, find all possible solutions and return them in the form of a list. 对该问题的扩展指出,找到所有可能的解决方案,然后以列表形式返回。 I tried to extend my solution by adding a column variable to the helper method, which starts at 0 to keep track of one complete solution and the start of the next. 我试图通过向helper方法添加列变量来扩展我的解决方案,该变量从0开始,以跟踪一个完整的解决方案和下一个完整的解决方案的开始。 Thus the base case becomes 因此,基本情况变为

if row == n and col == n:
   return True

But that approach doesn't work as every successive recursive call ends up in the wrong column. 但是这种方法不起作用,因为每个连续的递归调用最终都在错误的列中结束。 Can someone help extend this solution to find all possible solutions. 有人可以帮助扩展此解决方案以找到所有可能的解决方案。

Great question! 好问题! N-queens is also a great recursive problem :) You are actually really close to getting what you want and you don't have to modify your code too much. N-queens也是一个很大的递归问题:)实际上,您实际上已经很接近想要的东西了,您不必修改太多代码。

A good way to think about it is to understand the two different problems you are looking at. 进行思考的一种好方法是了解您正在研究的两个不同问题。 Your current approach is using backtracking to find the first solution possible. 您当前的方法是使用回溯来找到第一个可能的解决方案 What you want to do is find all solutions , a similar problem that just requires you to think about your base case differently. 您要做的就是找到所有解决方案 ,这是一个类似的问题,只需要您对基本情况进行不同的考虑即可。

In your current setup, if your base case returns True, the parent call will short circuit and return True as well. 在当前设置中,如果基本情况返回True,则父调用将短路并返回True。 This is ideal when trying to find just any single solution because once we found one that works, we know we can stop looking. 当尝试查找任何单个解决方案时,这是理想的选择,因为一旦找到可行的解决方案,我们就知道可以停止寻找。 However, as a result, we don't keep exploring other paths. 但是,因此,我们不会继续探索其他途径。

A way to think about backtracking is that you are basically creating a tree of possible boards resulting from possible moves. 思考回溯的一种方法是,您基本上是在创建可能的棋盘树,这些棋盘可能来自可能的移动。 To find the first solution, as soon as you get to a leaf node, or a winning state, you return all the way back up. 为了找到第一个解决方案,一旦您到达叶子节点或获胜状态,便会一直返回。 However, what you want to do is instead keep traversing all the other paths of the tree and keep looking for leaf winning states and recording them along the way. 但是,您要做的是继续遍历树的所有其他路径,并继续寻找叶子获胜状态并记录整个过程。

So, a simple way to modify your current approach is to modify your base case so that instead of returning True, it records the state of the board, a winning state, in a variable tracking all solutions. 因此,一种修改当前方法的简单方法是修改基本情况,以使其不返回True,而是在跟踪所有解决方案的变量中记录董事会状态(获胜状态)。 Additionally, now in your recursive case, when you make the recursive call you don't check for if it returns True or False, but rather just keep chugging along in the for loop and trying all moves. 另外,现在在递归的情况下,当您进行递归调用时,您无需检查它是否返回True或False,而是继续在for循环中尝试并尝试所有动作。

I modified your solution like this and got there are 92 solutions, something that the internet confirms is true :) 我像这样修改了您的解决方案,然后得到了92个解决方案,互联网证实了这一点是真的:)

class Solution(object):
    def __init__(self):
        self.solutions = []

    def solveNQueens(self, n):
        """
        :type n: int
        :rtype: List[List[str]]
        """
        grid = [['.' for _ in range(n)] for _ in range(n)]
        solved = self.helper(n, 0, grid)
        print len(self.solutions)
        if solved:
            return ["".join(item) for item in grid]
        else:
            return None

    def helper(self, n, row, grid):
        if n == row:
            print "wooo"
            self.solutions.append(copy.deepcopy(grid))
            return
        for col in range(n):
            if self.is_safe(row, col, grid):
                grid[row][col] = 'Q'
                self.helper(n, row + 1, grid)
                grid[row][col] = '.'

I hope this helps! 我希望这有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM