问题描述:(8皇后)
在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上
问有多少种摆法。
N皇后问题,是回溯法的典型例子,从第一行第一列的位置开始放置皇后,先固定行,在列上进行移动,当前行没有合适的位置可以安放皇后时则开始回溯到上一行。
#include <stdio.h>
#include <math.h>
#include <malloc.h>
void nQueens(int *x,int n);//求解n皇后问题
int place (int *x,int k);//判断是否可以在第k行第x[k]列摆放皇后
int sum=0;
int main()
{
int n;
int *x;//存放求解结果的数组首地址
scanf("%d",&n);
x=(int*)malloc(sizeof(int)*(n+1));//动态分配数组空间,x[0]空闲
nQueens(x,n);
printf("%d",sum);
return 0;
}
int place(int *x,int k)
{
int i;
for(i=1; i<k; i++)//对前k-1行,逐行考察
{
if((x[i]==x[k])||(fabs(x[i]-x[k])==fabs(i-k)))//在同一列或在同一斜线上
return 0;
}
return 1;
}
void nQueens(int *x,int n)
{
int k;
k=1;
x[k]=0;//进入循环后即执行了x[k]++,变为了第一列;
while(k>0)
{
x[k]++;
while(x[k]<=n&&!place(x,k))//每一列均进行判断
x[k]++;//下一列
if(x[k]<=n)//找到了一个位置可以摆放皇后
{
if(k==n)
sum++;//输出
else
{
k++;//移到下一行
x[k]=0;//从第一列开始考虑
}
}
else
k--;
}
}
容易知道,8皇后的所有可能解有8!种,即把12345678进行全排列即可。
由于C++有库函数可直接处理全排列问题,而且这样任意两个皇后必然身处不同行,不同列。
只需要判断是否在同一对角线即可。这样也算是一种比较简单的解法。
#include<bits/stdc++.h>//真的好用的头文件
using namespace std;
int total;//个数
bool check(int * a,int number)
{
for(int i=0; i<number; i++)
{
for(int j=i+1; j<number; j++)
{
if(fabs(a[i]-a[j])==fabs(i-j))//只需要判断有没有在同一对角线上的皇后即可。
{
return false;
}
}
}
return true;
}
int main()
{
int number;//全排列的长度
scanf("%d",&number);
int * x = (int*)malloc(sizeof(int)*(number+1));//x为指向这连续n+1个int的int指针
for (int i=0; i<number; i++)
{
x[i] = i+1;
}
do
{
if(check(x,number))//此位置可以摆放皇后
total++;
}
while(next_permutation(x,x+number));
printf("%d",total);
return 0;
}
关于皇后问题,时间复杂度一直是比较被看重的。这里由于当时没怎么学懂,就先不做分析了。
当皇后数目小于10的时候,两种写法出结果的时间都很快,马上就可以出来。
比较大的时候,全排列解法的速度就明显慢于回溯法。
但是当n大于14的时候,回溯法也需要好久才可以出结果。