以5皇后为例递归实现:考虑每行只放置一个皇后、每列也只能放置一个皇后,那么如果把n列皇后所在的行号依次写出,那么就会是1-n的一个排列。上图a中的排列为24135,对于b来说就是35142。于是就只需要枚举1-n的所有排列,查看每个排列对应的放置方案是否合法,统计合法的方案。
由于当到达递归边界时生成了一个排列,所以需要再其内部判断方案是否合法,即遍历每两个皇后,判断他们是否在同一对角线上。
#include<cstdio>
#include<stdlib.h>
const int maxn=10;
int n,P[maxn],hashTable[maxn]={false}; //P[]数组是用来储存皇后的位置排列,例如24135,hashTable[x]为true时表示x这个数在P[]中
int count=0;
void generateP(int index)
{
if(index==n+1)
{
//需要判断达到边界条件的排列是否满足n皇后条件
bool flag=true;//flag为true表示当前的排列为一个合法的方案
for(int i=1;i<=n;i++)//遍历任意两个皇后
{
for(int j =i+1;j<=n;j++)
{/*,以n=5为例:针对这里为什么是j=i+1,这是因为当i=1时j有2 3 4 5,当i=2时有3 4 5,其中的1 与当i=1时
有1 2 和2 1 这两种求绝对值是一样的,但是不能出现相同的例如 2,2 这就相当于p[2]
等于某个x p[2]也等于某个相同的x
这是不允许的,因为这样做后就相当于p[index]只有4个了而不是5个了结果就会出错,
所以要选择跳过2 2 这一项,就从j=i+1开始迭代
。对于一个已经在内部排列好的一个排列P它也不可能出现两个相同的坐标如,
P[2] P[2],应该是两个不同的坐标。例如一个合法的方案:
P[2]=1 P[4]=2 P[1]=3 P[3]=4 P[5]=5;
*/
if(abs(i-j)==abs(P[i]-P[j]))
{
flag=false;
}
}
}
if(flag) count++;
return;
}
for(int x=1;x<=n;x++)
{
if(hashTable[x]==false)
{
P[index]=x;
hashTable[x]=true;
generateP(index+1);
hashTable[x]=false;//处理完了p[index]为x 的子问题
}
}
}
int main()
{
n=8;
generateP(1);
printf("合法的方案有:%d",count);
}