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

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

1 问题描述

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

2 解题思路

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

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

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


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

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

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

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

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

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

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

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

由此,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

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

以下是使用ABT算法求解皇后问题Python代码: ``` def is_valid(board, row, col): for i in range(row): if board[i] == col or \ board[i] - i == col - row or \ board[i] + i == col + row: return False return True def backtrack(board, row, n): if row == n: return True for col in range(n): if is_valid(board, row, col): board[row] = col if backtrack(board, row + 1, n): return True return False def asynchronous_backtracking(position, domains, n): if len(position) == n: return position var = max(domains, key=lambda x: len(domains[x])) for val in domains[var]: pos_copy = position.copy() domains_copy = {k: v.copy() for k, v in domains.items()} pos_copy[var] = val domains_copy[var] = {val} if all(len(domains_copy[k]) > 0 for k in domains_copy): if backtrack(pos_copy, 0, n): result = asynchronous_backtracking(pos_copy, domains_copy, n) if result is not None: return result return None n = 4 position = {i: None for i in range(n)} domains = {i: set(range(n)) for i in range(n)} result = asynchronous_backtracking(position, domains, n) print(result) ``` 该代码首先定义了一个`is_valid`函数,用于检查当前位置是否合法。然后定义了一个普通的回溯算法函数`backtrack`,用于求解N皇后问题。最后定义了一个使用ABT算法的函数`asynchronous_backtracking`,该函数从所有未赋值的变量中选择一个具有最小剩余值的变量,然后对该变量的每个可能值进行尝试,直到找到一个可行解或无法继续搜索为止。 在主程序中,将变量和其域初始化为字典,然后调用`asynchronous_backtracking`函数求解皇后问题。最后输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值