//n皇后问题效率更高的解法
#include <iostream>
using namespace std;
void search(int step);
const int maxn=100;
int n,ans=0;
int a[maxn];
int vis[3][maxn];//“3”表示3种问题,vis[0][]表示"是否同列",vis[1][]表示"是否同主对角线",vis[2][]表示"是否同副对角线"
int main()
{
cin>>n;
search(0);
cout<<ans<<endl;
return 0;
}
void search(int step)//step可看作是 行
{
int i,j;
if (step==n)
{
ans++;
for (i=0;i<n;i++)
cout<<a[i];
cout<<endl;
}
else for (i=0;i<n;i++)//遍历 列
{
if (!vis[0][i] && !vis[1][step+i] && !vis[2][step-i+n])//判断 列(i),主对角线(step+i),副对角线(step-i+n) 是否已经有皇后了
{
a[step]=i;//把该 列数 放入数组a中以便打印各种情况的解
vis[0][i]=vis[1][step+i]=vis[2][step-i+n]=1;//标记当前位置为1,说明已经有皇后
search(step+1);//递归到下一个皇后
vis[0][i]=vis[1][step+i]=vis[2][step-i+n]=0;//恢复为“未放”状态
//如果在回溯法中使用了辅助的全局变量,则一定要即时把它们恢复原状。特别地,若函数有多个出口,则需在每个出口处回复被修改的值
}
}
}
/*回溯法:在某种情况下,递归函数将不再递归调用它自身,而是返回上一层调用,这种现象成为回溯(backtracking)。
递归枚举算法常被成为回溯法*/
//要满足"八皇后",实际上就是恰好每行每列放置一个皇后.
//如果用a[step]表示"第step行"皇后的"列编号"(即皇后的坐标为(step,a[step])),则问题变成了全排列生成问题
#include <iostream>
using namespace std;
void search(int);
const int maxn=10;
int n,ans=0;//n表示要求n皇后的问题("八"皇后问题的话,n就是8);ans用来计数有多少种解法
int a[maxn];//数组a用来表示“列”
int main()
{
cin>>n;
search(0);
cout<<ans<<endl;
return 0;
}
void search(int step)
{
int i,j;
if (step==n) ans++;//递归边界:只要走到这里,说明所有皇后都必然不冲突
else for (i=0;i<n;i++)
{
int ok=1; //ok是标记变量,用来判断该皇后是否与前面所放置的皇后有冲突,1代表无冲突,0代表有冲突
a[step]=i; //尝试把第step行(个)的皇后放在第i列
for (j=0;j<step;j++) //判断第step行(个)的皇后所放的位置是否与前面的皇后有冲突
if (a[step]==a[j] || step-a[step]==j-a[j] || step+a[step]==j+a[j])
{
ok=0;
break;
}//一旦发现皇后有冲突,ok=0,并马上退出判断循环,并选择其他列
//***"a[step]==a[j]"用来判断是否同列
//***"step-a[step]==j-a[j]"和"step+a[step]==j+a[j]"用来判断是否在同一对角线
if (ok) search(step+1);//如果ok=1,即第step行(个)皇后放置成功,然后就继续递归求第step+1行(个)皇后位置
}
}
N皇后问题解的个数
1
1
2
0
3
0
4
2
5
10
6
4
7
40
8
92
9
352
10
724
11
2680
12
14200
13
73712
14
365596
15
2279184
16
14772512
17
95815104
18
666090624
19
4968057848
20
39029188884
21
314666222712
22
2691008701644
23
24233937684440
24
227514171973736
25
2207893435808352