首先题目如下
问题描述
给定一个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
这里题目要求放置白皇后和黑皇后,我们可以先放置白or黑皇后,然后再放置另一个,思路如下
-
首先使用一个二维数组map对输入的进行存放,然后对map的每一行的每一列进行遍历,如果是1,则表示可以放置
-
找到可以放置的位置(即是在二维数组map中对应数为1)之后,对是否可以放置进行判断,判断同一行,列,斜线是否有同色的皇后
private static boolean Judge(int r, int c, int s) { //只对在当前所判断的行之前的行,还没有放置的行就不判断了,反正也还没东西 //判断对应列是否有冲突 for(int i = 0; i <= r; i++) { if(arr[i][c] == s) return false; } //判断左对角线是否有冲突 for(int i = r-1, j = c-1; i>=0 && j >= 0; i--, j--) { if(arr[i][j] == s)return false; } //判断右对角线是否有冲突 for(int i = r-1, j = c+1; i >= 0 && j < n; i--, j++) { if(arr[i][j] == s)return false; } return true; }
-
全部判断完后则对另外一种颜色的皇后进行放置,我们可以用不同的数字来区分皇后,如在map中2表示白皇后,3表示黑皇后,便于判断
完整代码如下
import java.util.Scanner;
public class BASIC_27_2nQueen {
//设置全局变量
static int n, Count = 0;
static int arr[][];
public static void main(String[] args) {
//获取输入
Scanner sc=new Scanner(System.in);
n = sc.nextInt();
arr = new int[n][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < n;j ++) {
arr[i][j] = sc.nextInt();
}
}
//从第0行放置白色棋子(2为白色,3为黑色)
Put(0, 2);
System.out.println(Count);
}
/**
* 放置棋子
*
* @param r 行号
* @param s 类型
*/
private static void Put(int r, int s) {
//展示当前棋盘
//Show();
//已经判断完所有结果
if(r == n) {
if(s == 2) { Put(0, 3); }
else Count++;
return;
}
//还未判断完所有行,则循环判断该行的每一列
for(int i = 0; i < n; i++) {
//该位置不可以放皇后,绕开
if(arr[r][i] != 1) continue;
//进行放置可行性判断
//可以放置
if(Judge(r, i, s)) {arr[r][i] = s;}
//不可以放置
else continue;
Put(r+1, s); //往下一层递归
arr[r][i] = 1; //用于后面回溯,将状态还原
}
return; //循环找不到结果,返回上一层
}
private static void Show() {
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
System.out.println("---------------------------");
}
private static boolean Judge(int r, int c, int s) {
//只对在当前所判断的行之前的行,还没有放置的行就不判断了,反正也还没东西
//判断对应列是否有冲突
for(int i = 0; i <= r; i++) {
if(arr[i][c] == s) return false;
}
//判断左对角线是否有冲突
for(int i = r-1, j = c-1; i>=0 && j >= 0; i--, j--) {
if(arr[i][j] == s)return false;
}
//判断右对角线是否有冲突
for(int i = r-1, j = c+1; i >= 0 && j < n; i--, j++) {
if(arr[i][j] == s)return false;
}
return true;
}
}
其中回溯的地方要好好理解
//还未判断完所有行,则循环判断该行的每一列
for(int i = 0; i < n; i++) {
//该位置不可以放皇后,绕开
if(arr[r][i] != 1) continue;
//进行放置可行性判断
//可以放置
if(Judge(r, i, s)) {arr[r][i] = s;}
//不可以放置
else continue;
Put(r+1, s); //往下一层递归
arr[r][i] = 1; //用于后面回溯,将状态还原
}
return; //循环找不到结果,返回上一层