// n皇后
#include <stdio.h>
#include <string.h>
#define MAX 15
int n; //n queen
int cur; //cur row
int A[MAX]; //the ith row's queen put in the A[i]th column
int tot = 0; // total nums
//cur 为当前遍历到的行。
//从第1~n列中选择一列,使当前皇后放到此位置时,与已经放好的1~cur-1行的皇后不冲突(即不在同一行、同一列、两个对角线上)
void search(int cur)
{
int i, j;
if (cur==n+1) //找到n个皇后的位置,打印出
{
for (i=1; i<cur; i++)
printf("%d ", A[i]);
printf("\n");
tot++;
return;
}
for(i=1; i<=n; i++) //遍历1~n列找到其中的一列可以用来放置当前的皇后
{
int ok = 1;
A[cur] = i;
for (j=1; j<cur; j++) //判断是否与之前已经放置的1~cur-1行的皇后有冲突
if (A[cur] == A[j] || cur-A[cur] == j-A[j] || cur+A[cur] == j+A[j]) //在同一列/两个对角线上
{ ok = 0; break; }
if (ok) //找到继续需找下一个皇后
search(cur+1);
}
}
int main()
{
while (scanf("%d", &n)!=EOF)
{
memset(A, 0, sizeof(A));
tot = 0;
search(1);
printf("%d\n", tot);
}
return 0;
}
注意到上面程序中判断第i列是否能放当前cur行的皇后的效率比较低,可以改进。
用一个全局变量vis[2][ ] 来保存某列、某主对角线、某副对角线已经被皇后占用。
这样就可以直接判断第i行是否可以放当前的皇后了。
void search2(int cur)
{
int i, j;
if (cur == n+1)
{
for (i=1; i<cur; ++i)
printf ("%d ", A[i]);
printf ("\n");
tot++;
return ;
}
for (i=1; i<=n; ++i)
{
if (!vis[0][i] && !vis[1][i+cur] && !vis[2][cur-i+n]) //判断是否可以放置当前皇后(效率比前面的高)
{
A[cur] = i;
vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 1; //修改全局变量的值使当前皇后放置位置的列、两条对角线被占用
search2(cur+1);
vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 0; //回溯,一定要将前面修改过的值改回来!
}
}
}
第一次写这个程序时将循环计数变量i,j误设置为全局变量,导致程序运行结果不正确。这是一个递归程序,i,j应该为局部变量,才不会导致进一步递归时程序破坏上一次递归栈的局部数据!!
参考文献:《算法竞赛入门经典》 刘汝佳 编著