在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。
分析:把二维数组分为n层n列,层层搜索,每当找到位置,就把该位置的行列及斜线位置设为不可达(+1操作,值为零时该位置可达。)搜索下一层。如果能到达最底层,则找到一种摆法。
我以为每个点最多能被标记四次,标记一次的点为皇后位置。把棋盘打印出来发现并不是。
没想到更好的剪枝方法,速度并不快。n为14,3185ms。
其中一个皇后(星为皇后),填充颜色的位置加一操作
#include <stdio.h>
int sum;
int checkerboard[16][16];
void fun( int k, int n)
{
if( k == n)
{
sum++;
/****打印棋盘
for( int j = 0; j < n; j++ )
{
for( int k = 0; k < n; k++ )
printf("%d ",checkerboard[j][k]);
printf("\n");
}
printf("\n");
*/
return;
}
for( int i = 0; i < n; i++ )
{
if(checkerboard[k][i]==0)
{
for( int j = 0; j < n; j++ )
{
///十字线
checkerboard[k][j]++;
checkerboard[j][i]++;
///斜十字线
if(k-j>=0 && i-j>=0)
checkerboard[k-j][i-j]++;
if(k-j>=0 && i+j<n)
checkerboard[k-j][i+j]++;
if(k+j<n && i-j>=0)
checkerboard[k+j][i-j]++;
if(k+j<n && i+j<n)
checkerboard[k+j][i+j]++;
}
fun( k+1, n );
for( int j = 0; j < n; j++ )
{
///十字线
checkerboard[k][j]--;
checkerboard[j][i]--;
///斜十字线
if(k-j>=0 && i-j>=0)
checkerboard[k-j][i-j]--;
if(k-j>=0 && i+j<n)
checkerboard[k-j][i+j]--;
if(k+j<n && i-j>=0)
checkerboard[k+j][i-j]--;
if(k+j<n && i+j<n)
checkerboard[k+j][i+j]--;
}
}
}
}
int main()
{
int t;
scanf("%d", &t);
for( int i = 1; i <= t; i++ )
{
int n;
scanf("%d", &n);
for( int j = 0; j < n; j++ )
{
for( int k = 0; k < n; k++ )
checkerboard[j][k] = 0;
}
sum = 0;
fun(0, n);
printf("%d\n", sum);
}
return 0;
}