时间限制 1000ms 内存限制 65536K
题目描述
给定一个 n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入 n 个黑皇后和 n 个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n 小于等于 8。
输入格式
输入的第一行为一个整数 n,表示棋盘的大小。
接下来 n 行,每行 n 个 0 或 1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为 0,表示对应的位置不可以放皇后。
输出格式
输出一个整数,表示总共有多少种放法。
样例输入1
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出1
2
样例输入2
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出2
0
【思路】
这道题可以看成是两个八皇后问题,我们可以先把所有的黑皇后放入棋盘中的合适位置,这里用和正常八皇后问题的递归函数求解即可,然后在黑皇后全部放入的情况下尝试放入白皇后,当所有的白皇后都可被放入时即存在一组解。只是这里判断有无冲突的函数bool notDanger(int r, int c)有所区别,对于黑皇后而言,除了当前位置不能与之前的皇后同列同斜线以外,这个位置必须是可放位置,即chess[r][c]==1,对白皇后同理,而且白皇后不能处于和已经放好的黑皇后相同的位置上面去。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n, ans;
int chess[10][10];
int x1[10], x2[10];
//先放入黑皇后,再放入白皇后
bool notDanger1(int r, int c) {//判断黑皇后是否冲突
if (0 == chess[r][c]) return false;
for (int i = 0; i < r; i++) {
if (x1[i] == c) return false;
if (abs(r - i) == abs(c - x1[i])) return false;
}
return true;
}
bool notDanger2(int r, int c) {//判断白皇后是否冲突
if (0 == chess[r][c]) return false;
if (x1[r] == c) return false;//注意黑白皇后不能重叠
for (int i = 0; i < r; i++) {
if (x2[i] == c) return false;
if (abs(r - i) == abs(c - x2[i])) return false;
}
return true;
}
void queen2(int k) {//在第k行放入白皇后
if (k == n) {
ans++;
return;
}
for (int i = 0; i < n; i++) {
if (notDanger2(k, i)) {
x2[k] = i;
queen2(k + 1);
x2[k] = -1;
}
}
}
void queen1(int k) {//在第k行放入黑皇后
if (k == n) {
queen2(0);
return;
}
for (int i = 0; i < n; i++) {
if (notDanger1(k, i)) {
x1[k] = i;
queen1(k + 1);
x1[k] = -1;
}
}
}
int main() {
while (scanf("%d", &n) == 1) {
ans = 0;
memset(x1, -1, sizeof(x1));
memset(x2, -1, sizeof(x2));
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
scanf("%d", &chess[i][j]);
}
queen1(0);
printf("%d\n", ans);
}
return 0;
}