深度搜索入门题n皇后问题
问题描述:
要在n*n的国际象棋棋盘中放n个皇后,使任意两个皇后都不能互相吃掉。规则是皇后能吃掉同一行、同一列、同一对角线的棋子。(即不能放置在有被吃危险的位置)
Input:一个整数n
Ouput:Q种放置方法下每种方法所对应n个皇后的具体坐标和Q的值
Sample Input:1
Sample Output:<1,1> 1
先贴一下代码,再浅谈思路。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
using namespace std;
int n,i;//n记录是多少个皇后的问题,i记录的是第几个皇后
int a[501];//数组下标表示行号,数组值表示列号
int sum;//记录有多少种解法
bool judge(int a[],int N) //检测当前位置的皇后是否是合法的
{
for(int j=1;j<N;j++)
{
if(abs(a[j]-a[N])==abs(j-N) || a[j]==a[N])//见下面注释
return false;
}
return true;
}
void print_ans(){//打印输出每一种解的方案。
for(int j=1;j<=n;j++)
cout<<"<"<<j<<","<<a[j]<<">"<<" ";
cout<<endl;
}
void solve(int i){//使用该函数来实现递归检测八皇后合法性
if(i>n){//递归出口,每出现一次,意味着得到了一种解
sum++;
print_ans();//输出答案;
return ;
}
for(int j=1;j<=n;j++){//每一行8列都尝试走一遍
a[i]=j;
if(judge(a,i)){//判断当前皇后是否满足要求,满足则递归至下一层
solve(i+1);
}
}
}
int main(){
cin>>n;
sum=0;
solve(1);//
cout<<"一共有多少组解:"<<sum;
}
思路概括:分为三个大模块
1:判断模块:判断皇后当前所在位置是否满足条件,即不与任意皇后在同一列、同一行、同一对角线的相邻位置。对于对角线问题的限制可以用abs()函数进行左对角和右对角的简化。
2:深搜模块:当前位置满足条件时,继续递归,进行深度搜索(dfs)。
3:打印模块:对于每一种解法,我们要将其输出打印。
对代码的一些额外注释:
if(abs(a[j]-a[N])==abs(j-N) || a[j]==a[N])
/*数组a[]下标代表横坐标(行),数组a[]的值代表纵坐标(列)
j+a[j] == N +a[N] (斜向正方向)j-a[j] == N -a[N] (斜向反方向)
加绝对值可以合并为正文代码所示。*/
if(i>n){//递归出口,每出现一次,意味着得到了一种解
sum++;//当i=n代表一次完整的递归结束,故当i>n即可表示出现一种解,sum+1
另外:因为本题的搜索方式是每一行求一个皇后的位置,所以同一行不会有冲突,不需要考虑。
关于深搜还是有很多不懂的地方,递归也是本周刚刚搞懂一点皮毛,代码也有不完美的地方,如何在短时间内用博客的形式把头脑的东西表达出来也是一个难题。