题目
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就是列出,并且为了方便坐标系,我们让最下方一行为第一行).