Problem Description:
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
Input:
共有若干行,每行一个正整数N≤12,表示棋盘和皇后的数量;如果N=0,表示结束。
Output:
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
Sample Input:
1
8
5
0
Sample Output:
1
92
10
思路:
以下图的 4x4 棋盘为例:
显然每行棋盘有且仅有一个皇后,所以我们可以依次在第0、1、2、3行放置皇后,每一行再按列放置,每放置一个皇后前判断该位置是否允许放置,每放置一个皇后后将其所在行、列、斜线的棋盘标记为不可放置。
由于我们是依次按行放置皇后,所以放置时不需要判断该行是否可放置。
用visy[]数组标记列:vis[i]为1表示第i列不可放置
图中红色的线为主对角线,蓝色的线为副对角线。
可以观察到,每条主对角线上棋盘的行数与列数之差为定值(图中三条主对角线的x-y对应三个值),所以每放置一个皇后,将vis1[x-y]赋值为1(x、y为该皇后所在行、列)。
副对角线上棋盘的行数与列数之和为定值(图中三条副对角线的x+y对应三个值),所以每放置一个皇后,将vis2[x+y]赋值为1。
下面是代码:
#include <stdio.h>
#include <string.h>
#include <map>
using namespace std;
int n,ans;
const int maxn=14;
int visy[maxn],vis1[2*maxn];
map<int,int>vis2;
void dfs(int k){
if(k==n){
ans++;
return ;
}
for(int i=0;i<n;i++)
if(!visy[i] && !vis1[k+i] && !vis2[k-i]){
visy[i]=vis1[k+i]=vis2[k-i]=1;
dfs(k+1);
visy[i]=vis1[k+i]=vis2[k-i]=0;
}
}
int main(){
while(scanf("%d",&n),n){
memset(visy,0,sizeof(visy));
memset(vis1,0,sizeof(vis1));
vis2.clear();
ans=0;
dfs(0);
printf("%d\n",ans);
}
return 0;
}