N皇后问题 盲目搜索之深度优先搜索(python)

N皇后问题
N皇后问题是国际象棋的扩展,在N×N的棋盘上放置N个皇后,使得每一个皇后都不会攻击到其余的任一皇后(皇后可以攻击和它在同一行、同一列或同一对角线上的任何棋子)。
N皇后问题 盲目搜索之深度优先搜索(python)_第1张图片
深度优先搜索算法
深度优先搜索 Depth-First-Search 总是扩展搜索树的当前边缘结点中最深的节点。搜索很快的推进到搜索树的最深处的结点,该结点称之为叶子结点,它没有后继,当这些结点扩展完之后,就从边缘结点中去掉,然后回溯到下一个未扩展后继的深度稍浅的结点,搜索过程如下图所示。
N皇后问题 盲目搜索之深度优先搜索(python)_第2张图片
与宽度优先搜索使用 FIFO 队列不同,深度优先搜索使用 LIFO, Last In First Out 的队列结构,即最新生成的结点最早被选择扩展,因此,为了实现方便,深度优先搜索算法一般抛弃 LIFO 队列而采用递归式结构实现。

求解思路:
棋盘的行可以用树的深度来表达,因此每一行只有一个皇后,她们不会同行。棋盘的列可以用一个长度为N的一维数组来记录是否放置过皇后。观察棋盘的行和列的特点,可以发现如下规律:
N皇后问题 盲目搜索之深度优先搜索(python)_第3张图片
棋盘的左斜线\可以用一个数字表达,因此所有的左斜线可以用一个长度为2N−1的一维数组来记录是否放置过皇后,同理,右斜线/也可以用一个长度为2N−1的一维数组来记录是否放置过皇后。

具体实现
代码给了详细的注释


```python
# -*- coding:utf-8 -*-

class Solution:

    def __init__(self, n=0):
        self.vis = [[]]             #用于标记是否存在皇后的二维列表(初始值全为0)
        self.ans = 0                #用于存储答案(N皇后方案数,初始值0)
        self.n = n                  #用于存储皇后数量n


    def solveNQueens(self):
        """求解N皇后问题(调用self.DFS函数)
        :rtype: self.ans: int    #返回N皇后放置方案数
        """
        # 产生一个3行50列的数组,第一行代表左斜线,第二行代表所在的列,第三行代表有索引,初始值都为0
        self.vis = [[0 for j in range(50)] for i in range(3)]
        self.DFS(1,self.n)  # 递归
        return self.ans

    def DFS(self, row, n):
        """深度优先搜索N皇后问题的解空间
        :type: row: int      #NxN棋盘的第row行
        :type: n: int        #皇后数量n
        :rtype: None         #无返回值
        """
        if row == n+1:   # 行数大于皇后的个数,说明这个方案可行,方案数加1,递归结束(递归结束条件),
            self.ans += 1
            return
        for i in range(1,n+1,1):
            # vis[0][row-i+n] == 0 row-i即行的索引减去列的索引,左斜线等于0,左斜线没有放置皇后,+n是为了防止产生负数
            # vis[1][i] == 0 第i列为0
            # vis[2][row+i] == 0  即所在的右斜线上并没有存放皇后,row+i即行索引加上列索引,同一右斜线的行索引加列索引所得的值相等。
            if self.vis[0][row-i+n] == 0 and self.vis[1][i] == 0 and self.vis[2][row+i] == 0: # 第row行第i列可以存放皇后
                self.vis[0][row-i+n] = self.vis[1][i] = self.vis[2][row+i] = 1  # 将对应的列,左斜线、右斜线都置为1
                self.DFS(row+1,n)  # 存放下一个皇后
                # 如果下一个皇后的位置无法正确放置,则调整当前皇后的放置位置
                self.vis[0][row-i+n] = self.vis[1][i] = self.vis[2][row+i] = 0
                # 继续本次循环,知道找到本行的列中有合适的存放位置为止,如果本行无合适位置,则继续返回上一层

if __name__ == '__main__':
    queen = Solution()
    queen.__init__(8)
    ans = queen.solveNQueens()
    print(ans)

以八皇后为例,最后输出92种方案数。
N皇后问题 盲目搜索之深度优先搜索(python)_第4张图片

你可能感兴趣的:(python,算法,人工智能)