很经典的一道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)