Bootstrap

蓝桥杯:N皇后

目录

题目描述

输入描述

输出描述

题目分析:DFS

AC代码(Java):


题目描述

在 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;
    }
}

;