本题此次采用搜索思想,因为题目中要求N<=10所以BFS和DFS姑且还在时间复杂度允许范围内。
算是个DFS练习吧。
题目分析:
从第一行开始安放皇后,产生node1,此后第二场再按要求安放,产生node2,以此类推会出现符合题意的若干答案。
根据题目要求,皇后之间不能同行同列同斜线,所以假设新皇后的坐标位置为(x,y)原本皇后坐标为(i,j)有如下关系。
1.因为不同行不同列,所以对应x=i和y=j是不行的。
2.因为不同斜线,所以abs(i-x)=abs(j-y)也是不行的
满足如上俩个要求就能安放新的皇后。
重点:当我们在不断产生node的同时我们也会发现有些支路还没到最后一步就已经无法再产生node了,这时我们就要进行“枝剪”,把已经没有产生正确答案可能的支路给减掉。
关键点就是剪掉支路。
DFS代码
/*n皇后问题*/
#include <bits/stdc++.h>
using namespace std;
int ans,n,col[12]={0};
bool check(int r,int l)
{
for(int i=0;i<r;i++)
{
if(col[i]==l||abs(col[i]-l)==abs(i-r))
{
return false;
}
}
return true;
}
void DFS(int r)
{
if(r==n)
{
ans++;/*说明已经有一条路走到了尽头,我们要结束他了,并且还要把他算作一种答案*/
}
else
{
for(int i=0;i<n;i++)/*一共有n列*/
{
if(check(r,i))
{
col[r]=i;
DFS(r+1);
}
}
}
}
int main()
{
int t;
for(cin>>t;t;t--)
{
memset(col,0,sizeof(col));
ans=0;
cin>>n;
DFS(0);/*从第0行开始安放皇后*/
cout<<ans<<endl;
}
return 0;
}
解释一下
check这里
if(col[i]==l||abs(col[i]-l)==abs(i-r))
其实就是你要在第r行安防皇后,你需要遍历0到r-1行是否都满足条件
而我们在DFS中的这一步 col[r]=i;知道在之前安放的过程中入过第r行的第i列满足条件我们就将其标记在col数组中,这样col[i]就是这一行符合要求的那一列的列数。
DFS这里
我们最后如果已经安排到了r=n的时候,因为r是从0开始的,我们能够确认所有的皇后都安放完毕,所以可以结束递归并且记录这一种状态(ans++)
如果没有满足r=n的话就继续对第R行来安放皇后,皇后共有n列可以选择所以我们要for(int i=0;i<n;i++)也就是把这一行的所有列都试试看。然后这一行结束了再继续向下一行探索 DFS(r+1);
主函数这里
为了保证正确性,每一次都要清零。
那么枝剪体现在了那里呢?
for循环中如果连续n次都判定if(false)那么这条路就到此结束了,也不会继续执行DFS(r+1)
为什么看上去有些不像DFS呢
的确,,,,这个一层一层搜索的时候会先在这一层找到"正确答案"然后再继续往下走,而且也没有返回节点这一操作。一个是因为枝剪,另一个就是因为这个题实际上是在一步步找最终状态,而不是找到一个值就结束了,跟何况这个最终状态还是多样的,所以必须遍历完所有的可能,这就感觉不像是DFS,其实BFS也可以写只是因为代码写来起来比较烦我没写。
明天写迭代加深搜索的埃及分数问题。