【算法】【回溯篇】第1节:八皇后问题

15 篇文章 1 订阅
7 篇文章 0 订阅

本期任务:介绍算法中关于回溯思想的几个经典问题

【算法】【回溯篇】第1节:八皇后问题

【算法】【回溯篇】第2节:解数独问题

【算法】【回溯篇】第3节:正则表达式问题

【算法】【回溯篇】第4节:全排列问题

【算法】【回溯篇】第5节:组合问题

【算法】【回溯篇】第6节:子集问题

【算法】【回溯篇】第7节:0-1背包问题


一、问题描述

在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法,并将对应的摆法展示
在这里插入图片描述

二、算法思路

1. 策略选择

  • 八皇后问题是典型的“多阶段决策最优解”问题:每个棋子决策一次,共决策8次;最优解是满足同一行、同一列或同一斜线上不冲突。
  • 不满足无后效性:一个棋子摆放之后,可能导致不存在可行解,即后面的状态可能影响前面状态,故不能使用动态规划。
  • 本问题也不满足贪心选择性,即无法通过局部最优的选择,能产生全局的最优选择,故不能使用贪心策略。
  • 本题使用回溯算法暴力穷举所有可能的排列方式,并通过剪枝策略进行优化。

2. 回溯算法思路

  • 暴力穷举,每一行都可能有8种可摆放位置,所有可能的摆放方式共有 8 8 8^8 88,穷举过程遵循深度优先搜索规则。
  • 维护一个长度为8的数组res,用于保存每一行的棋子的列号。
  • 剪枝策略:利用数组res,若当前棋子位置与前面棋子出现行、列或斜向冲突时跳过。
  • 结算情形:8个棋子都放置好了

以4皇后为例,画递归树如下:
在这里插入图片描述


三、Python代码实现

class Solution:

    def totalNQueens(self, n):
        self.size = n  # 问题规模(皇后数)
        self.res = [-1] * self.size  # 用来记录每一行中皇后在第几列
        self.count = 0  # 记录符合要求的排列个数

        self.helper()  # 回溯求解
        return self.count

    def helper(self, row=0):
        """回溯的主逻辑"""
        if row == self.size:  # 棋子都放置好了,打印结果
            self.printRes()  # 打印结果
            self.count += 1  # 符合要求的排列个数加一
            return

        for col in range(self.size):  # 每一行都有8中放法
            if self.isOk(row, col):  # 有些放法不满足要求
                self.res[row] = col  # 第row行的棋子放到了column列
                self.helper(row + 1)  # 考察下一行

    def isOk(self, row, col):
        """判断当前位置是否安全"""

        for r in range(row):
            if self.res[r] == col:  # 同列不安全
                return False
            elif row + col == r + self.res[r]:  # 主对角线不安全
                return False
            elif row - col == r - self.res[r]:  # 副对角线不安全
                return False
        return True

    def printRes(self):
        """打印结果"""
        for i in range(self.size):
            for j in range(self.size):
                if self.res[i] == j:
                    print(' Q ', end='')
                else:
                    print(' * ', end='')
            print()
        print()


def main():
    client = Solution()
    client.totalNQueens(n=4)
    print(client.count)


if __name__ == '__main__':
    main()

运行结果

 *  Q  *  * 
 *  *  *  Q 
 Q  *  *  * 
 *  *  Q  * 

 *  *  Q  * 
 Q  *  *  * 
 *  *  *  Q 
 *  Q  *  * 

2
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值