1. 问题:在棋盘上放置8个皇后,使得它们互不攻击,每个皇后的攻击范围为同行同列和同对角线,要求找出所有解。
思路:不难发现恰好每行每列放置一个皇后,如果用C[x]表示第x行皇后的列编号,则问题变成了全排列生成的问题。
流程图如下:
代码实现:
#include<iostream>
#include<cstdio>
using namespace std;
int n,cnt;
int C[100];
void search(int row){
if (row == n)cnt++;
else for (int i = 0; i < n; i++){//尝试i~n-1列
bool ok = true;
C[row] = i;
for (int j = 0; j < row;j++)
if (C[j] == C[row] || row - C[row] == j - C[j] || row + C[row] == j + C[j]){
ok = false; break;
}
if (ok)search(row + 1);
}
}
int main()
{
cin >> n;
search(0);
cout << cnt << endl;
system("pause");
return 0;
}
2. 八皇后问题的优化
由于每次判定能不能在该列放入当前皇后,而判断的过程都要检查是否与已经放入的皇后冲突。为了提高程序效率,可以分别用三个一维数组记录已经占用的列、主对角线和副对角线。把它们合并为一个二维数组vis[2][]。
那么如果该位置可以放入当前皇后,那么在递归调用前应该修改vis[2][],使得该递归之路都知道该列、该主对角线和该副对角线已经被占用。但是,在回溯的过程,应该把vis[2][]数组还原为原来的样子,以便于解答树的横向拓展。
具体的函数可以为下面:
#include<iostream>
#include<cstdio>
using namespace std;
int n,cnt;
int vis[2][100];
void search(int row)
{
if (row == n)cnt++;
else for (int i = 0; i < n; i++){
if (!vis[0][i] && !vis[1][row-i+n] && !vis[2][row+i]){
vis[0][i] = vis[1][row-i+n] = vis[2][row+i] = 1;
search(row + 1);
vis[0][i] = vis[1][row-i+n] = vis[2][row+i] = 0;
}
}
}
int main()
{
cin >> n;
search(0);
cout << cnt << endl;
system("pause");
return 0;
}