问题描述
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2
样例输入
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
0
思路:先放黑皇后,将黑皇后合理的摆放好后,再放白皇后。放黑皇后时,限制条件为该点不能为0,因为是从上到下遍历每一行,一行只放一个黑皇后,所以只需考虑该点所在的列是否放过皇后(vy[10]数组标记该列是否放过皇后,该点值为1表示该列已经放了一个黑皇后,不能再放黑皇后;该点值为2表示该列已经放了一个白皇后,不能再放白皇后;该点值为3表示该列已经放了一个黑皇后和一个白皇后,不能再放黑皇后和白皇后),该点所在的左对角线是否放过黑皇后(vd1[20]数组,含义同上),该点所在右对角线是否放过黑皇后(vd2[20]数组,含义同上)。
每在点(i,j)放一个黑皇后,将该点mp[i][j]置为0,表示该点已经被用过。黑皇后放完后,开始放白皇后,判断条件同黑皇后。
参考于计蒜客蓝桥杯省赛训练营的例题讲解
AC代码
1 #include <bits/stdc++.h>
2 using namespace std;
3 int mp[10][10]; //存储地图
4 int vy[10]; //存储该列的信息
5 int vd1[20]; //存储左对角线信息
6 int vd2[20]; //存储右对角线信息
7 int n, ans;
8 void dfs(int x, int p) { //参数x表示当前搜索到第几行,参数p表示当前在放什么颜色的皇后,p = 1表示放黑皇后,p = 2表示放白皇后
9 if (x == n && p == 2) { //从第0行 ~ n - 1行遍历,若当前遍历到第n行,且白皇后已放完,方案数加一
10 ans++;
11 return;
12 }
13 if (x == n) { //从第0行 ~ n - 1行遍历,若当前遍历到第n行,表示黑皇后已放完,开始从第0行放白皇后
14 dfs(0, p + 1); //将p变为2,表示开始遍历白皇后
15 return;
16 }
17 for (int i = 0; i < n; i++) { //遍历每一列
18 //在该点可以放皇后的条件:
19 //该点不为0; mp[x][i] != 0
20 //该点所在的列没有同颜色皇后; vy[i] != 3 && vy[i] != p
21 //该点所在的左对角线没有同颜色皇后; vd1[x + i] != 3 && vd1[x + i] != p
22 //该点所在的右对角线没有同颜色皇后; vd2[x - i + n] != 3 && vd2[x - i + n] != p
23 if (mp[x][i] != 0 && vy[i] != 3 && vy[i] != p && vd1[x + i] != 3 && vd1[x + i] != p && vd2[x - i + n] != 3 && vd2[x - i + n] != p) {
24 mp[x][i] = 0; //将该点置为0,表示将皇后放在该点
25 vy[i] += p; //更新该点所在的列
26 vd1[x + i] += p; //更新该点所在的左对角线
27 vd2[x - i + n] += p; //更新该点所在的右对角线
28
29 dfs(x + 1, p); //搜索下一行
30
31 vy[i] -= p; //回溯,恢复现场
32 vd1[x + i] -= p;
33 vd2[x - i + n] -= p;
34 mp[x][i] = 1;
35 }
36 }
37 }
38 int main() {
39 cin >> n;
40 for (int i = 0; i < n; i++) { //输入棋盘
41 for (int j = 0; j < n; j++) {
42 cin >> mp[i][j];
43 }
44 }
45 //先放黑皇后,再放白皇后
46 dfs(0, 1); //从第0行开始搜索,1表示先放黑皇后
47 cout << ans << endl; //输出方案数
48 return 0;
49 }