2020/10/28 n皇后问题

深度优先遍历-n皇后问题

题目

n-皇后问题是指将 n 个皇后放在 n∗n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
现在给定整数n,请你输出所有的满足条件的棋子摆法。

输入格式
共一行,包含整数n。

输出格式
每个解决方案占n行,每行输出一个长度为n的字符串,用来表示完整的棋盘状态。
其中”.”表示某一个位置的方格状态为空,”Q”表示某一个位置的方格上摆着皇后。
每个方案输出完成后,输出一个空行。
输出方案的顺序任意,只要不重复且没有遗漏即可。

数据范围
1≤n≤9
输入样例:
4
输出样例:
.Q…
…Q
Q…
…Q.
…Q.
Q…
…Q
.Q…

题目分析

首先,题目明显可以看出是分步骤枚举.第一步枚举第一行,第二步枚举第二行… 此类问题都可以使用DFS来做.
需要注意的是标记问题,题中要求每行,每列,对角线只能有一个,因此要建三个变量存储是否满足条件,需要注意的是,当前步骤只会影响自己之后的步骤;对于自己同级别及其之后的是不产生影响的.
用题目举例: 第一行的第一个位置放皇后,则第二行及以后就不能放了,但是如果第一行的皇后位置换位置了,那后面的规则也修改了.
用生活举例:自己的家规只能适用于自己和自己的孩子,一旦对于别人及其孩子,这个家规就要修改了.

此类题目模板:

dfs(int k){
if(k=某结束条件) 输出结果(一般表示遍历到结尾了) return;
for(int i;i<n;i++){//当前步骤枚举
if(当前枚举满足条件) 
st[i]=true;//对当前枚举标记
dfs(k+1);//对下一步骤枚举
st[i]=false;//当前的枚举都结束了,那标志也该取消了,因为马上换同级别的来枚举了 
}
}

源代码


import java.util.*;
class Main{
 static int N=10;
 static boolean[] col=new boolean[N];
 static boolean[] dg=new boolean[2*N];
 static boolean[] udg=new boolean[2*N];
 static char[][] g=new char[N][N];
 public static void main(String[] args){
  Scanner sc=new Scanner(System.in);
  int n=sc.nextInt();
   for (int i = 0; i < n; i ++ )
            for (int j = 0; j < n; j ++ )
                g[i][j] = '.';

  dfs(0,n);
 }
 public static void dfs(int k,int n){

  if(k==n){
   for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
     System.out.print(g[i][j]);
    }
    System.out.println();
   }
   
   System.out.println();
   return;

  }
  for(int i=0;i<n;i++){
   if(!col[i]&&!udg[k+i]&&!dg[k-i+n]){
    g[k][i]='Q';
    col[i]=udg[k+i]=dg[k-i+n]=true;
    dfs(k+1,n);
    col[i]=udg[k+i]=dg[k-i+n]=false;
    g[k][i]='.';//这也是在回溯
   }

  }

 }

}

代码说明

  • 输出图的思路:首先建立数组g[i][j]表示各个位置的符号,并初始化全为'-',然后通过枚举找到合适的Q的位置,再将对应的位置将'-'替换为'Q',自此图以修改完毕. 需要注意的是,不要忘记回溯,同时防止多个枚举图重叠,需要将图也进行回溯.否则出现的情况,第一个图没问题,但是第二个图是在第一个图上加Q,到最后可能全图都是Q了,因此在当前支路所有都枚举完成后,要再替换回去(也是回溯的一种).
  • 对于对角线的理解: 我们希望找到横纵坐标满足某种条件的位置,他们都在一条对角线上,又数学知识我们不难知道y=x+b,满足这个关系的x和y都在对角线上,因此我们可以让y-x作为记录其的角标,为了防止角标出现负值,加一个n表示正数即可;同理y=-x+b,则x+y作为记录的角标.(这里其实y就是行数,x就是列出,并且为了方便坐标系,我们让最下方一行为第一行).
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值