蓝桥杯-N皇后(DFS)
0.题目
【题目描述】
有一个N*N的矩阵棋盘和N个棋子,现在需要将N个棋子按要求放置在矩阵方格中。
要求:
1、任意两颗棋子不能在同一行
2、任意两个棋子不能在同一列
3、任意两个棋子不能在同一对角线上(下面的红线都是对角线)
根据以上要求,问N个棋子放置到N*N矩阵中有多少种放置方案?
【输入描述】
输入一个正整数N(1<N<11),表示N*N的矩阵方格和N个棋子数量。
【输出描述】
输出N个棋子按要求放置到N*N的矩阵中,有多少种放置方案?
1.题解
1.1 DFS搜索
思路
对于不能同行,整体按行顺序从上到下进行遍历(外层循环)
难点主要是纠正同列和对角线的情况,利用记忆化存储存储之前节点实际皇后摆放位置,然后和当前皇后位置进行比较
如果发生冲突,放弃该位置; 如果不发生冲突, 可以选择该位置,也可以不选择该位置,同时更新当前chosen数组的值即可
代码
#include<bits/stdc++.h>
using namespace std;
// 表示第n行的皇后摆放的列位置
int chosen[11] = {-1};
int ans = 0;
int n;
// x表示当前已经选择了x个
void DFS(int x) {
if (x == n + 1) {
ans++;
return;
}
// // 选择该行放置的列位置i, [x][i],
// for (int i = 1; i <= n; i++) {
// if(x == 1) {
// chosen[x] = i;
// DFS(x + 1);
// } else {
// // 遍历之前的行, [j][chosen[j]]
// for (int j = 1; j < x; j++) {
// if ((chosen[j] != i) && (abs(chosen[j] - i) != abs(x - j))) {
// // 选择该位置
// chosen[x] = i;
// DFS(x + 1);
// // 不选择该位置
// chosen[x] = -1;
// }
// }
// }
// }
// 选择该行放置的列位置i, [x][i],
for (int i = 1; i <= n; i++) {
bool conflict = false;
chosen[x] = i;
// 遍历之前的行,判断有无冲突 [j][chosen[j]]
for (int j = 1; j < x; j++) {
if((chosen[j] == i) || (abs(j - x) == abs(chosen[j] - chosen[x]))){
conflict = true;
break;
}
}
// 没有冲突
if(!conflict){
DFS(x+1);
}
}
}
int main() {
cin >> n;
DFS(1);
cout << ans;
return 0;
}
优化版本
主要是封装了函数,使其更符合普遍模板
#include <bits/stdc++.h>
using namespace std;
int chosen[11] = {0};
int ans = 0;
int n;
// 判断是否会发生冲突(剪枝)
int PD(int k){
for(int i = 1; i < k; i++){
if(abs(k-i) == abs(chosen[k]-chosen[i])){
return 0;
} else if(chosen[k] == chosen[i])
return 0;
}
return 1;
}
// 判断返回条件
bool check(int a){
if(a > n){
ans++;
}
else return 0;
return 1;
}
void DFS(int x) {
if (check(x)) {
return;
}
// 尝试在第 x 行的每一列放置皇后 [x][i];
for (int i = 1; i <= n; i++) {
chosen[x] = i;
// 判断这一步是否冲突
if(PD(x)) {
DFS(x+1);
}else{
// 不需要清零,每次开头的chosen[x] = i;就可以实现刷新
// chosen[x] = 0;
continue;
}
}
}
int main() {
cin >> n;
DFS(1);
cout << ans << endl;
return 0;
}