经典问题。
但是方案却不唯一,记得很早的时候写过n个循环嵌套的版本。
现在想想蠢死了。
只有八皇后是否在同一直线斜线上判断方法也有多种。
首先一行一行(或者一列一列)填皇后这个应该是没的说的。判断斜线是个要点
法1就是打一个棋盘然后每填上一个皇后就把皇后的攻击范围全部标记。回溯的时候再把皇后的攻击范围全部改回去。
判断皇后能不能在那个格子很快。但是这个填改的过程应该很慢。
法2就是利用几何关心 n皇后 两个皇后处于左下右上对角线方向x1-x2=y1-y2
处于左上右下对角线方向x1-x2=y2-y1
下面这个代码并不能过(TLE)
#include <iostream>
#include <stdio.h>
using namespace std;
const int M=11;
int cb[M];
//int cbz[2M-1],cbf[2M-1]; //主对角线副对角线
int tot;
void dfs(int nnow,int naim)
{
if(nnow==naim)
tot++;
else
{
for(int i=0;i<naim;i++)
{
int f=1;
cb[nnow]=i;
for(int j=0;j<nnow;j++) //坏处就是这个循环 要遍历之前填过的皇后
if(cb[j]==i||nnow-j==cb[nnow]-cb[j]||nnow-j==cb[j]-cb[nnow])
{
f=0;
break;
}
if(f)
dfs(nnow+1,naim);
}
}
}
int main()
{
int n;
while(1)
{
scanf("%d",&n);
if(!n)
break;
tot=0;
dfs(0,n);
printf("%d\n",tot);
}
return 0;
}
坏处如上 这个方法要遍历填过去的皇后信息进行计算。
法3
#include <iostream>
#include <stdio.h>
using namespace std;
const int M=11;
int cbh[M]; //某行是否使用
int cbz[2*M-1],cbf[2*M-1]; //主对角线副对角线
int re[M];
int tot,n;
void dfs(int nnow)
{
if(nnow==n)
tot++;
else
{
for(int i=0;i<n;i++) //将在nnow列i行放皇后
{
int tmp=nnow+n-i;
if(!cbh[i]&&!cbz[nnow+i]&&!cbf[tmp])
{
cbh[i]=cbz[nnow+i]=cbf[tmp]=1;
dfs(nnow+1);
cbh[i]=cbz[nnow+i]=cbf[tmp]=0; //改回来
}
}
}
}
int main()
{
for(n=1;n<M;n++) //TLE的主要原因在此 这个问题必须打表
{
tot=0;
dfs(0);
re[n]=tot;
}
while(1)
{
scanf("%d",&n);
if(!n)
break;
printf("%d\n",re[n]);
}
return 0;
}
直接利用几何关系,在放置皇后时更新行以及主副对角线信息。
这个题超时的关键在于应该打表。
提示是以后这种答案组数较少但是每组答案计算耗时较长的应该用打表的方法。
另附这个题居然直接这样也可以过……
#include <iostream>
#include <stdio.h>
using namespace std;
const int M=11;
int re[M]={0,1,0,0,2,10,4,40,92,352,724};
int main()
{
int n;
while(1)
{
scanf("%d",&n);
if(!n)
break;
printf("%d\n",re[n]);
}
return 0;
}