经典N皇后(N-Queens)问题的经典 Python 求解(LeetCode Problem 51 52)

最近做了LeetCode上关于 N 皇后问题的题目,下面将最普通且经典的解题思路和源码分享如下,恳请网友们批评指正:

1 问题描述

LeetCode 的 51 题和 52 题是经典的 N 皇后问题,其游戏规则很简单:在一个 n * n 的棋盘上放 n 个皇后,每两个皇后不能在同一行,同一列,同一条斜线上。51 题要求输入 n ,返回所有解;52 题要求输入 n ,返回解的个数。

经典N皇后(N-Queens)问题的经典 Python 求解(LeetCode Problem 51 52)_第1张图片

2 解题思路

N 皇后最经典的解法即为回溯法,本文将介绍其最简单,最经典的回溯法思想。(潜台词就是用时会比较长)

回溯法的核心思路是从某个根节点开始,以深度优先搜索的方式寻求解集,如果发现无解就回溯到最近的可选择的节点去搜索另一种情况的解法,以 n = 4 为例:

游戏开始,在未做尝试之前我们认为第一行的每一列都可以放置皇后,首先尝试在第一行第一列放置皇后 1 :


这时第一行就不能放皇后了(不能与皇后 1 在同一行),要从第二行开始放,第二行第一列不能放(不能与皇后 1 在同一列),第二行第二列也不能放(不能与皇后 1 在同一条斜线上),所以皇后 2 可以放在第三列或第四列上,这时先尝试第二行第三列:

这时发现,第三行第一列不能放皇后(不能与皇后 1 在同一列),第二列也不可以(不能与皇后 2 在同一条斜线上),第三列也不可以(不能与皇后 2 在同一列),第四列也不可以(不能与皇后 2 在同一条斜线上),这时我们便回溯到最近的有选择的节点,即尝试在第二行第四列放置皇后 2:

类似上一段的推导我们发现这样也不行。这时第一行第一列放置皇后 1 的所有可能性都尝试完了,所以我们只能回溯到更上一层,尝试在第一行第二列放置皇后 1 :

同样,只能在第二行第四列放置皇后 2 :

在第三行第一列放置皇后 3 :

在第四行第三列放置皇后 4 :

由此我们就得到了一个解。

解题思路大致如下图,余下过程与上述类似:

经典N皇后(N-Queens)问题的经典 Python 求解(LeetCode Problem 51 52)_第2张图片

由此,N 皇后问题解题思路介绍完成。

(其实不难发现,根据图形的对称性,当我们在第一行第三列和第四列放置皇后 1 时,其情况分别与第二列和第一列相同。本文对此特点不作详细阐述,编程代码也未做体现)

编码实现

一般情况下,我们使用递归函数来实现回溯法。本文的递归函数传入两个参数,一是当前已放置的皇后的坐标组(用二元组列表表示),二是当前行数。

所以 Problem 51 的 Python 代码如下:

def NQueens(queenList,line): # 递归函数

    # 当行数等于皇后数量时,记录结果
    if line == queenNum:
        temp = []
        for i in range(queenNum):
            s = ''
            for j in range(queenNum):
                if [i,j] in queenList:
                    s += 'Q'
                else:
                    s += '.'
            temp.append(s)
        ans.append(temp)
    
    # 否则,进行判断
    else:
        for i in range(queenNum):
            flag = 0
            for node in queenList:
                # 当这个位置与其他皇后在同一列或同一条斜线上时
                if i == node[1] or abs(line-node[0]) == abs(i-node[1]):
                    flag = 1

            # 列表为空为特殊情况,即表示第一行,放在哪一列都可以
            if queenList == [] or flag == 0:
                queenList.append([line,i])
                NQueens(queenList,line+1)
                queenList.pop(-1) # 恢复之前的状态

class Solution:
    def solveNQueens(self, n: int) -> List[List[str]]:
        global ans,queenNum
        ans = []
        queenNum = n
        NQueens([],0) # 初始时没有皇后,且从第一行开始放置皇后。
        return ans

Problem 52 的 Python 代码如下:

def NQueens(queenList,line):
    global ans
    if line == queenNum:
        ans += 1
    else:
        for i in range(queenNum):
            flag = 0
            for node in queenList:
                if i == node[1] or abs(line-node[0]) == abs(i-node[1]):
                    flag = 1
            if queenList == [] or flag == 0:
                queenList.append([line,i])
                NQueens(queenList,line+1)
                queenList.pop(-1)

        
class Solution:
    def totalNQueens(self, n: int) -> int:
        global ans,queenNum
        ans = 0
        queenNum = n
        NQueens([],0)
        return ans

以上就是文章的全部内容,希望可以帮到大家,文章内容如有不足或者错误,恳请大家批评指正。

你可能感兴趣的:(算法)