问题描述
- 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
- 我们看洛谷上的该题描述
大致思路
1.按照行的顺序进行
2.从第一列到最后一列进行枚举。判断当前列是否能够放置,如果不能,进行下一列的判断
3.请结合注释了解相关具体过程
代码
解法一:
#include <bits/stdc++.h>
using namespace std;
int n, sum;
int a[15];
//判断模块
bool judge(int a[], int N) {
//如果前面这些点中有至少一个出现同列或者斜率相等,说明不可行,返回false
for(int i=1; i<N; i++) {
if((a[i]==a[N]) || (abs(a[i]-a[N])==abs(N-i))) {
return false;
}
}
return true;
}
//打印模块
void print_all(){
for (int i = 1; i <= n ; ++i) {
cout << a[i] << " ";
}
cout << endl;
}
//搜索模块
void DFS(int i) {
if(i > n) {
sum++;
if(sum <= 3) {
print_all();
}
return;
}
for (int j = 1; j <= n ; ++j) {
a[i] = j;
if(judge(a, i)) {
DFS(i+1);
}
}
}
int main(){
cin >> n;
DFS(1);
cout << sum;
return 0;
}
解法二:
#include <bits/stdc++.h>
using namespace std;
int n, sum;
//a[i]记录当前i行摆放棋子的所在列
int a[15];
//由数学归纳法可知,当两点在正对角线上,则i+j相等
//当两点在反对角线上,i-j相等;此时可能出现负数,则都加上n
//以下三个数组分别代表i列,左下往右上对角线,左上往右下对角线
bool b[15], c[50], d[50];
//打印模块
void print_all(){
for (int i = 1; i <= n ; ++i) {
cout << a[i] << " ";
}
cout << endl;
}
//搜索模块
void DFS(int i) {
if(i > n) {
sum++;
if(sum <= 3) {
print_all();
}
return;
}
for (int j = 1; j <= n ; ++j) {
//看是否此处能放
if(b[j]==false && c[i+j]==false && d[i-j+n]==false) {
//记录当前棋子状态
a[i] = j;
b[j] = true;
c[i+j] = true;
d[i-j+n] = true;
//进行下一个棋子的摆放
DFS(i+1);
//此处在DFS语句之后,代表上面的DFS进行不下去了。则此时进行回溯
b[j] =false;
c[i+j] = false;
d[i-j+n] = false;
}
}
}
int main(){
cin >> n;
//从第一行开始
DFS(1);
cout << sum;
return 0;
}