【蓝桥杯】 N皇后问题

        很经典的一道DFS的题目,值得好好研究!

问题描述:

        

题目描述

在 N×N 的方格棋盘放置了 N 个皇后,使得它们不相互攻击(即任意 2 个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成 45 角的斜线上。你的任务是,对于给定的 N,求出有多少种合法的放置方法。

输入描述

输入中有一个正整数 N≤10N≤10,表示棋盘和皇后的数量

输出描述

为一个正整数,表示对应输入行的皇后的不同放置数量。

输入输出样例

示例 1

输入

5

输出

10

 问题分析:

        思路:

        经典的题目,思路无需多言,使用DFS,深度优先搜索,按行放皇后,先考虑第一行的几个位置放上皇后,然后考虑皇后放在第一行的一个位置下,这个时候考虑第二个皇后可以放在哪,再考虑第三个皇后....当确定了最后一个皇后满足结束条件的位置时,这个时候,答案数+1.

        模板:

        DFS问题是有对应的模板进行求解的,大致分为三个函数:

                1.一个是DFS搜索本身的函数,如何进行下一步的迭代 DFS()

                2.一个是判断当前DFS退出的条件,比如到达了边界退出  check()

                3.一个是判断当前状态是否满足题目所给要求,是否需要继续进行DFS.  判断函数:pd()

        注意事项:

        从模板的三个函数入手,首先先看check函数,即程序运行到什么时候结束:

check函数:

        很明显,题目所给的是N皇后,如果我确定了N个皇后所在的位置,那么给答案加上1,然后再退出即可,否则则继续向下搜索。

pd函数:

        判断函数则是判断当前皇后放的位置是否满足条件,本题皇后需要满足的不同行,不同列,不在同一条斜线,由于我们是一行一行考虑放置皇后,所以只需要考虑皇后不同列,不同斜线的问题。

DFS函数:

       我认为在DFS问题中,最难理解的就是DFS函数的这个递归问题,我理解的也并不是很到位,所以还需要多做题。

        本问题的DFS函数,主要分为几个阶段,第一个阶段就是check函数,判断我是否可以停止DFS了,如果还没到停止的时候,算了....这里直接上代码!!!在代码里面细说。

代码分析:

        输入:

import os
import sys
l=[0 for i in range(15)] #用于存放第i个皇后所在的列数
n=int(input())
res=0 #记录最后答案

        l数列:由于题目所给最多10个皇后,所以我们定义一个l数列储存每个皇后的列的位置。(这里实际也隐含了,我第一个皇后放在第一行的某一列,第二个皇后放在第二行的某一列)

        n:则为输入的皇后数量

        res:则为满足题目条件的答案数

           check函数:

def check(x):#停止条件为搜索的皇后数大于要求皇后数
    if x>n:
        global res
        res=res+1
        return 1
    else:
        return 0

很容易理解,x为当前到第几个皇后了,比如到x=1就是第一个皇后

举个例子:如果一共有5个皇后,则第5个皇后判断完之后,会继续判断第6个皇后,但是我们只需要判断5个皇后即可,所以6>5,所有皇后位置确定了,给答案+1,结束即可

        pd函数:


def pd(x):
    for i in range(1,x):
        if abs(x-i)==abs(l[x]-l[i]):
            return 0
        elif l[x]==l[i]:
            return 0
    return 1

        pd()判断函数也很好理解,如果两个皇后之间的斜率为正负1的话,那么则在同一条斜线上,x,i表示的是第x,i个皇后,其实也意味着第x个皇后放在第x行,因为我们是按行进行的。

        l[x]==l[i]判断的则是这两个皇后是否为同一列        

        这里的话是有一个从1,到x-1的遍历,则是我需要判断当前这个函数和之前的每一个皇后是否共斜线,是否共列。

        DFS函数(最重要的部分):

总算到这了,DFS函数

def DFS(x):
    if check(x):
        return
    else:
        for i in range(1,n+1):
            l[x]=i
            if pd(x):
                DFS(x+1)
            else:
                continue

但实际上DFS函数也非常的简单,x表示第x个皇后。

我们首先check这个第x个皇后是否可以结束了,如果可以结束了,答案+1,并且直接结束这一次的结果。

如果没有结束,比如这个时候x=1,进行到第一个皇后,我们则需要进入else的判断,

这里的话有一个遍历,从1到n,这里是遍历如果我的第1个皇后在第1列,在第2列...的情况。

然后接下来就是判断第1个皇后是否满足题目所给条件,很明显,第1个皇后会直接返回1,随便放都可以的。

所以当前节点可以的话,我DFS(x+1),即我确定了第一个皇后的位置(当然第一个皇后的位置可以在第1,2,3,4....列),我再判断第二个皇后的位置在哪...不断递归进行。最后当x大于皇后数的时候,把答案加1即可。

完整代码:

        虽然我不知道在DFS函数这一块,我讲清楚了没有,但是没关系,还是得多刷,多模仿,算法算法,法的本质还是先模仿,再提出的过程,而进行蓝桥杯比赛,要求的只是我们模仿的能力,只需要明白这个题用了什么算法,然后模仿这个算法即可。多模仿!共勉

        

import os
import sys
l=[0 for i in range(15)] #用于存放第i个皇后所在的列数
n=int(input())
res=0 #记录最后答案
def check(x):#停止条件为搜索的皇后数大于要求皇后数
    if x>n:
        global res
        res=res+1
        return 1
    else:
        return 0


def pd(x):
    for i in range(1,x):
        if abs(x-i)==abs(l[x]-l[i]):
            return 0
        elif l[x]==l[i]:
            return 0
    return 1

def DFS(x):
    if check(x):
        return
    else:
        for i in range(1,n+1):
            l[x]=i
            if pd(x):
                DFS(x+1)
            else:
                continue

DFS(1)#从第一个皇后开始搜索
print(res)

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值