题目
n个皇后放在 n ∗ n n*n n∗n的棋盘上,并且皇后彼此之间不能相互攻击。
分析思路
用穷举法需要尝试 88 =16,777,216 种情况,所以肯定不行
回溯法,第一个应该想到这种方法,需要按照树状进行一层层尝试,如果无法放置,后续的放置都不再考虑,回退到上一步继续。
第一次放置,第一行
列1 | 列2 | 列3 | 列4 |
---|---|---|---|
皇 | × | × | × |
× | × | 0 | 0 |
× | 0 | × | 0 |
× | 0 | 0 | × |
第一列标记已放置
column[1]=1
左上到右下标记已放置
left[1-1+4]=left[4]=1
右上到左下标记已放置
right[1+1]=right[2]=1
皇后位置:
queen[1]=1
第二次放置,第二行
列1 | 列2 | 列3 | 列4 |
---|---|---|---|
皇 | × | × | × |
× | × | 皇 | × |
× | × | × | × |
× | 0 | × | × |
第三列标记已放置
column[3]=1
左上到右下标记已放置
left[2-3+4]=left[3]=1
左上到右下标记已放置
right[2+3]=right[5]=1
皇后位置:
queen[3]=1
第三次放置,第三行
row=3,colum=1, 因为:column[1]=1,所以无法放置
row=3,colum=2, 因为:right[3+2]=right[5]=1,所以无法放置
row=3,colum=3, 因为:column[3]=1,所以无法放置
row=3,colum=4, 因为:left[3-4+4]=left[3]=1,所以无法放置
第4次放置,第三行无法放置,则不再进行
回退到第二行,清空第二行、第三列放置皇后影响的位置。尝试第二行、第四列放置。
代码
package org.example.queen;
public class NQueen {
//皇后个数
int n = 4;
//解个数
int solveNum = 0;
//记录皇后左上到右下是否可放置皇后,长度为2*n,这条线上横坐标、纵坐标之差全部相等,y=x+b;
int[] left = new int[2*n+1];
//记录皇后右上到左下是否可放置皇后,长度为2*n,这条线上横坐标、纵坐标之和全部相等,y=-x+b;
int[] right = new int[2*n+1];
//记录每一列皇后是否可以放置皇后
int[] column = new int[n+1];
//记录皇后位置,从第0行开始
int[] queen = new int[n+1];
//回归
public void regression(int row){
//如果已经有n个皇后,则打印
if(row == n+1){
solveNum++;
System.out.println("解"+solveNum+":");
for (int i = 1; i <= n ; i++) {
for (int j = 1; j <= n; j++) {
if(queen[i]==j){
System.out.print("*"+"\t");
}else {
System.out.print("0"+"\t");
}
}
System.out.println();
}
}else {
//循环当前行每一列
for (int i = 1; i <= n ; i++) {
//如果当前列可以放皇后,并且当前行、列右上到左下,左上到右下可以放皇后
if(column[i] == 0 && left[row-i+n] == 0 && right[row+i] == 0){
//放置皇后
column[i] = 1;
left[row-i+n] = 1;
right[row+i] = 1;
queen[row] = i;
//迭代下一行
regression(row+1);
//回退,当前列放完后,换下一列
//已放置的皇后需要清空
column[i] = 0;
left[row-i+n] = 0;
right[row+i] = 0;
queen[row] = 0;
}
//如果不可以放,则进行下一列,减少程序搜索路径
}
}
}
public static void main(String[] args) {
//从第0行开始计算。
new NQueen().regression(1);
}
}