这题用到的思路就是深搜,但是深搜还是需要点优化,不然会超时。
for(int i=1;i<=n;i++) {
boolean flag=false;
if(!book[i]) {
for(int j=1;j<step;j++)
if(step-j==Math.abs(i-nums[j])) {
flag=true;
break;
}
}
if(flag==true)
continue;
nums[step]=i;
book[i]=true;
dfs(nums,step+1,n);
book[i]=false;
}
}
先说明一下变量都代表的什么意思,因为题目中行是默认升序的,我们只需要判断应该在哪一列就行,用i来遍历所有的列,j是来遍历所有的行,step表示是到达了第几行,nums数组的下标表示行数,下标对应的数组元素表示棋子放在该行的哪一列。
for(int j=1;j<step;j++)
if(step-j==Math.abs(i-nums[j])) {
flag=true;
break;
}
}
上边的代码就是对角线的判断,对角线判断条件是 行-行==列-列,如果满足这个条件,表示在同一个对角线上,就不能要,从第一行开始判断,如果第step行-第j行 == 第i列-第j列的绝对值,因为step肯定比j大,所以不用带绝对值,而列数不一样,有可能第一行在最后一列,第二行在第三列这种情况,所以列数的差需要带个绝对值。
if(flag==true)
continue;
nums[step]=i;
book[i]=true;
dfs(nums,step+1,n);
book[i]=false;
如果flag==true表示构成了对角线,所以就continue,到下一列,如果没有对角线,说明这个点是可以进入nums数组的,将其添加进去,并且标记这个点已经走过,接着遍历下一行,返回的时候要把标记去掉。
import java.util.*;
public class Main {
static boolean[] book;//用来表示是否访问过
static int cnt=0;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
book=new boolean[n+1];//下标从1开始,所以就是n+1
int[] nums=new int[n+1];
new Main().dfs(nums,1,n);
System.out.println(cnt);
}
void dfs(int[] nums, int step, int n) {
if(step==n+1) {//说明数字走完了,要退了
cnt++;
if(cnt<=3) {//因为只用输出前三个
for(int i=1;i<=n;i++) {
System.out.print(nums[i]+" ");
}
System.out.println("");
}
return ;
}
for(int i=1;i<=n;i++) {
boolean flag=false;
if(!book[i]) {
for(int j=1;j<step;j++) {
if(step-j==Math.abs(i-nums[j])) {
flag=true;
break;
}
}
if(flag==true)
continue;
nums[step]=i;
book[i]=true;
dfs(nums,step+1,n);
book[i]=false;
}
}
}
}