目录
题目描述
在 N×N 的方格棋盘放置了 N 个皇后,使得它们不相互攻击(即任意 2 个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成 45 角的斜线上。你的任务是,对于给定的 N,求出有多少种合法的放置方法。
输入描述
输入中有一个正整数 N≤10,表示棋盘和皇后的数量
输出描述
为一个正整数,表示对应输入行的皇后的不同放置数量。
输入
5
输出
10
题目分析:DFS
1.首先看题目要求,就是在一块N*N的棋盘上,放N个皇后,皇后能够正确放置的条件是:
I.同一行只能有一个皇后
II.同一列只能有一个皇后
III.以该皇后为中心,斜线上都不能有皇后。
知道了要求,我们在分析,N*N的棋盘,可以使用一个二维数组来处理,不过题目只是要求统计能成功在N*N的棋盘上放置N个皇后的方案数,并没有要输出具体的方法,所以我们可以偷个懒,用一维数组来存放数据,也就是array[0]代表第一行,array[1]代表第二行,然后array[0]就存放第一个皇后放置的行列,列的值,这样一个array[0],就同时拥有了行数和列数。
因为数组下标的递增性,我们就不需要管行数的冲突(同一行放置了超过一个皇后就算冲突),因为我们是以每一行为单位,计算是否能在该列放置皇后,这样只需要处理列的冲突和斜线的冲突。
关于斜线冲突的处理,我参考了这篇文章的两点是否处于一个斜线上:
也就是,行之差==列之差,那么就代表这两个点处于一条斜线上,我们只需要通过Math.abs判断两个点的行之差==列之差即可。判断思路如下 Math.abs( 点1的行 - 当前需要放置的点的行 ) == Math.abs( 点1的列- 当前需要放置的点的列), 就通过这样,判断当前的点和需要放置皇后的点是否处于同一斜线。
行,列,斜线的冲突解决之后,我们讲一下怎么递归调用。
首先递归要素1:设置出口,因为我们数组的下标就是行,也就是我们遍历到i的时候,那么就代表已经放了i个皇后,当i==N,那么就让方案数自增,然后结束本次的递归调用(return;)
递归要素2:确定如何触发递归调用,我们可以for循环放置列col,下标通过dfs(int row)进行传递,也就是行作为递归的传递条件,如果当前的列col能够放置皇后,那么我们继续调用dfs,让行数row自增,也就是这一行的皇后已经放置了,开始放置下一行的皇后。
只需要在循环的时候调用check()方法检查当前位置(row,col)能否放置皇后,如果能放置皇后,就放置皇后,然后到下一行,如果不能,就列自增,再往下找能够放置皇后的列数
AC代码(Java):
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
static int n;//需要放置的皇后数量
static int[] array;//用一维数组来存放数据,下标作为行,值作为列
static int result = 0;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//拿数据
n = scan.nextInt();
array = new int[n];
//dfs从0开始搜索可行方案
dfs(0);
System.out.println(result);
scan.close();
}
/*
*@para row:行数,代表开始从第一行放置皇后
*/
public static void dfs(int row){
//搜索完,如果行数=需要放置的皇后数量,那么代表该次搜索成功,能够放置N个皇后在N*N的棋盘上
if(row == n){
result++;
//结束本次搜索
return ;
}
//因为是一维数组,下标作为行数,那么行数肯定不会冲突,我们只需要每个下标对应的值给列,
//然后判断列数是否相同(一维数组的已经放入的元素是否有相同的)
//如果有相同的,代表列冲突,则取消本次放置
for(int col = 0;col<n;col++){
if(check(row,col)){
//check检查完毕,如果是true,则代表当前位置可以放置一个皇后,那么我们继续递归调用dfs
//继续找下一个皇后可以放在哪里
array[row] = col;
dfs(row+1);
}
}
}
/*
*@para row col:行和列,用来判断是否冲突(一行只能有一个皇后,一列只能有一个皇后,对应的斜线上也只能有一个皇后)
*/
public static boolean check(int row,int col){
//先循环判断列是否相同
for(int r = 0;r<row;r++){
//从0开始遍历,小于row是因为row是放的皇后数量,之后肯定没有放,只需要判断前面放的皇后和当前放的皇后是否冲突即可
//直接判断列是否冲突,斜线是否冲突。
//列冲突的条件就是array中存放的数值和当前想要放入的col冲突,那么就代表列冲突了
//斜线冲突的话,就是行之差==列之差,就代表这两个皇后在同一个斜线上,就肯定会冲突
if( (array[r] == col) || ( Math.abs(r-row) == Math.abs(array[r]-col) ) ){
//如果列,斜线有一个冲突,就返回false
return false;
}
}
//循环完之前放置的皇后,都没有冲突,代表该位置可以放置一个皇后
return true;
}
}