盲目搜索算法

​​​​​​

目录

任务描述

相关知识

N 皇后问题

问题分析

编程要求

测试说明


 

任务描述

本关任务:编写程序实现 N 皇后问题。

相关知识

为了完成本关任务,你需要掌握: N 皇后问题的思想及实现。

N 皇后问题

在 N 行 N 列的国际象棋上摆放 N 个皇后,使其不能互相攻击(即任意两个皇后都不能处于同一行、同一列或同一斜线上)。请问有多少种摆法,以及如何摆放这些皇后。这就是经典的 N 皇后问题。


图1 N 皇后问题

问题分析

根据问题求解的方法,我们先将问题表示出来:

  • 状态:棋盘上 0−N 个皇后的任一摆放都是一个状态;

  • 初始状态:N×N 的棋盘上没有皇后;

  • 算子:在棋盘上的任一空格摆放一个皇后;

  • 目标:N个皇后都在棋盘上,并且无法互相攻击。

设棋盘某一位置为(i,j),将第i+1行的N个空格位置都作为(i,j)的后继结点,那么N×N的棋盘则可以通过一个根结点连接为一棵N叉搜索树,棋盘第i行对应搜索树深度为i的结点层,树的根结点到叶子节点的路径序列就是一个棋盘的状态序列,应用深度优先搜索算法可以非常方便的求解。

由于状态空间会随着N呈现出爆炸式的增长,搜索会非常浪费时间,我们可以加一些限制条件,这样可以排除很多不必要地搜索:

  • 每一行只能放置一个皇后,那么对这一行其余的结点就不需要放置皇后了,也就是上面的建树过程,只以下一行棋盘空格作为后继结点,忽略本行其余空格;

  • 每一列只能放置一个皇后,下次搜索时就不要搜索已经放置过皇后的列了;

  • 每一斜对角线只能放置一个皇后。

棋盘的行可以用树的深度来表达,因此每一行只有一个皇后,她们不会同行。棋盘的列可以用一个长度为N的一维数组来记录是否放置过皇后。观察棋盘的行和列的特点。

编程要求

本关的编程任务是,补全右侧编辑 Begin-End 区间的代码,使函数 solveNQueens 和函数 DFS 实现指定功能 ,具体要求如下:

  • 在 solveNQueens 中,利用 DFS 函数实现N皇后问题求解,并返回方案总数;

  • 在 DFS 中,利用深度优先搜索算法的思想,递归求解N皇后问题。

测试说明

平台会对你编写的代码进行测试:

测试输入:1

预期输出:1

输入格式:整数,表示皇后数量。

输出格式:整数,表示 N 皇后放置方案总数。

代码部分

# -*- 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皇后放置方案数
        """
        #请在这里补充代码,完成本关任务
        #********** Begin **********#
        self.vis = [[0 for j in range(50)] for i in range(3)]
        self.DFS(1,self.n)  # 递归
        return self.ans
        #********** End **********#
    def DFS(self, row, n):
        """深度优先搜索N皇后问题的解空间
        :type: row: int      #NxN棋盘的第row行
        :type: n: int        #皇后数量n
        :rtype: None         #无返回值
        """
        #请在这里补充代码,完成本关任务
        #********** Begin **********#
        
        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)
       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值