问题描述:
在nXn格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于,在nxn格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。
算法分析
此题用回溯法求解,可以构造排列树解空间,假设两个皇后放置的位置分别为(xi,yi)和(xj,yj)
- 解向量:(x1,x2,…,xn)
- 显约束:x=1,2…n
- 隐约束:
- (1)不同列:xi≠xj
- (2)不处于同一正、反对角线:|xi-xj|!=|yi-yj|
算法实现
(1)递归实现
#include <iostream>
using namespace std;
const int maxn=100005;
int x[maxn]={0};
int sum=0,n;
bool constraint(int t)
{
for(int i=0;i<t;i++)
if(abs(i-t)==abs(x[i]-x[t])) return false;
return true;
}
void backTrace(int t)
{
if(t==n) sum++;
else{
for(int i=t;i<n;i++)
{
swap(x[i],x[t]);
if(constraint(t)) backTrace(t+1);
swap(x[i],x[t]);
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++) x[i]=i;
backTrace(0);
cout<<sum<<endl;
system("pause");
return 0;
}
(2)递推实现
bool place(int t)
{
for(int i=1;i<t;i++)
if(abs(i-t)==abs(x[i]-x[t])||x[i]==x[t]) return false;
return true;
}
int iterativeBack()
{
x[1]=0;
int k=1,sum=0;
while(k>0)
{
x[k]+=1;
while((x[k]<=n)&&!place(k)) x[k]+=1;//找到一个合法的k节点
if(x[k]<=n)
{
if(k==n) sum++; //到达终点
else x[++k]=0; //未到达终点
}
else k--; //不存在合法子节点
}
return sum;
}
复杂度分析
- 时间复杂度:T(n)=O(N!)
- 空间复杂度:S(n)=O(N)