问题描述
给定一个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
解题思路
n x n 的棋盘摆放n个黑皇后和n个白皇后,且同肤色皇后不能同行同列同对角线,则每行必定为一黑一白。可令2代表黑皇后,3代表白皇后,我们先将黑皇后安顿好再安顿白皇后。首先挨行检索有无皇后容身之处,前提要满足该位置为1,其次判断前几行放置的黑皇后是否与当前位置不同列且不同对角线,若以上条件都满足则将皇后放到当前位置(将当前位置设置为2),若不满足则检索该行下一位置,倘若整行都没有合适位置,则回溯至上一行移动黑皇后的位置,重复以上步骤,对于白皇后的操作亦是如此。另外,在一种方案检索完毕后,要记得还原棋盘,以便下一方案可行性的测试。
代码实现
import java.util.Scanner;
public class Main {
static int n, sum = 0;// n:棋盘边长(皇后数量),sum:不同摆法
static int[][] chess;// 棋盘
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
chess = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
chess[i][j] = sc.nextInt();// 初始化棋盘
}
}
dfs(0, 2);// 从第一行开始检索摆放皇后的位置 0为第一行的下标,用2代表黑皇后,3代表白皇后
System.out.println(sum);
}
static void dfs(int line, int queen) {
if (line == n) {
// 若n行都已放置皇后
if (queen == 2)// 若之前放置的为黑皇后
dfs(0, 3);// 从第一行开始检索白皇后的摆放位置
else// 若放置的为白皇后(则黑白皇后都已放置完毕)
sum++;// 摆放方案+1
} else {
// 尚未放置到最后一行
for (int j = 0; j < n; j++) {
if (chess[line][j] == 1 && check(line, j, queen)) {
// 判断该点是否满足皇后放置条件
chess[line][j] = queen;// 放置皇后
dfs(line + 1, queen);// 进行下一行的检索
chess[line][j] = 1;// 还原棋盘
}
}
}
}
static boolean check(int line, int row, int queen) {
for (int i = line - 1; i >= 0; i--) {
// 判断当前位置所在列是否有该皇后
if (chess[i][row] == queen)
return false;
}
for (int i = line - 1, j = row - 1; i >= 0 && j >= 0; i--, j--) {
// 判断反斜线上是否存在该皇后
if (chess[i][j] == queen)
return false;
}
for (int i = line - 1, j = row + 1; i >= 0 && j < n; i--, j++) {
// 判断斜线上是否存在该皇后
if (chess[i][j] == queen)
return false;
}
return true;
}
}