1.问题描述:
在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法
2.分析:
2.1 用数字表示摆放位置思路:
首先,每一行每一列都会有一个皇后,并且左右每个斜线都不能超过一个皇后,如果将皇后位置排列画到图上
皇后的摆放方式有2 的64次方中,如果将这些摆放方式作为数字,用数字的在第几位表示皇后在哪一行,每一位上的数字序号表示皇后在哪一列,即:
1758
1(1行1列)7(2行7列)5(3行5列)8(4行8列)
每一位只有8个数字选择,那么总共的摆放数量有 8的8次方,还是很大
其实不用每一个数字都拿来校验,可以在数字从第一位开始放置数字,第二位放置数字的时候校验是否与之前的皇后攻击,校验方法,将当前数字(列)在第几位(行)与之前的每一个数字对应的行列进行判断是否攻击,如果攻击则结束,否则将当前放置的数字加入到数字序列中,如果到达第八位(第八行)表示八个皇后都已放置完成,数量加一
判断攻击方式:
取出两个位置的行列(x1,y1),(x2,y2) 判断条件:
x1 != x2
y1 != y2
(x1-x2) != |(y1-y2)| //斜线向左或向右
代码如下:
#include <bits/stdc++.h>
typedef unsigned long long ULL;
using namespace std;
bool valid_queen(int num, int x, int idx) {
// 将数字转化为对应的坐标进行校验,判断是否存在列,行,斜线攻击
int col;
int tmp_num = num;
for (int i = 0; i < idx; i++) { // 遍历之前已经放置好的每一个皇后
if (tmp_num == 0) {
break;
}
int row = i + 1; // 之前已经放置的皇后的行
col = (tmp_num % 10); // 之前放置皇后的列
tmp_num /= 10;
if (col == x) {
return false;
}
if ((idx - row) == (x - col)) {
return false;
}
if ((idx - row) == -(x - col)) {
return false;
}
}
return true;
}
// 输入数字,填写的位数
int dfs(int num, int x, int idx) {
// 如果可以添加,则添加,同时判断如果位数满8则 返回1,位数未满8位dfs当前状态
bool valid = valid_queen(num, x, idx);
if (valid) {
num += x * (int) pow(10, idx - 1);
if (idx == 8) {
cout << num << endl;
return 1;
}
//在下一行添加皇后
int ans = 0;
for (int i = 1; i <= 8; i++) {
ans += dfs(num, i, idx + 1);
}
return ans;
} else {
// 如果无法继续添加,返回0
return 0;
}
}
int main() {
int s = dfs(0, 0, 0);
cout << "ans:" << s << endl;
return 0;
}