八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
解题思路:
- 采用穷举的方法,从棋盘第一行的第一个位置开始,检验皇后之间是否会相互攻击。如果会,继续判断下一格是否会互相攻击,如果不会互相攻击则在这个位置进行标记,并开始遍历下一行,查找满足条件的皇后位置,直到不能再继续放置皇后为止。
- 这时,我们可以做出简单的判断,当皇后数量为每行各一个时,它是满足摆放策略的,当没有放到最后一行时,这种情况是不满足条件的。当然满足摆放皇后位置的方法并不止一种,我们不能在查找过一次方案后就停止查找,因此我们在进行逐层遍历时要引入回溯的思想,再每次标记过位置查找下一行之后,我们还要记得取消我们的标记,这样才可以保证找到全部符合条件的情况。
例题:给定一个整数 n,打印出所有不同的 n 皇后问题的解决方案。每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
public class EightQueen {
public static void main(String[]args) {
char[][] ch= new char[8][8]; //定义n*n的棋盘
for(int i=0;i<ch.length;i++) { //对每个棋盘位置都标记为'.'
for(int j=0;j<ch.length;j++) {
ch[i][j]='.';
}
}
solveNQueens(0,ch); //调用递归的函数,从棋盘的第一行开始
}
public static void solveNQueens(int row,char[][] ch2) {
//如果遍历的行数大于棋盘的行数,说明我们遍历到了最后一行,满足要求
if(row>=ch2.length) {
for(int i=0;i<ch2.length;i++) { //打印这一种方案
for(int j=0;j<ch2.length;j++) {
System.out.print(ch2[i][j]);
}
System.out.println();
}
System.out.println();
}
for(int i=0;i<ch2.length;i++) { //依次逐行遍历,
if(check(row,i,ch2)) {
ch2[row][i]='Q'; //在每行的标记满足条件的皇后位置
solveNQueens(row+1, ch2); //递归,调用下一行
ch2[row][i]='.'; //取消我们之前的标记,避免影响下一次查找
};
}
}
//判断该位置是否适合标记皇后
private static boolean check(int row, int index, char[][] ch2) {
//值得注意的是因为我们采用的逐层遍历的思想,我们不需要再复杂的写一个不在同一行、同一列、同一斜线上的复杂函数
//我们只需要考虑,该位置的上方,左上方,右上方是否有冲突的皇后就可以了
int rightTop=index,leftTop=index;
for(int i=row-1;i>=0;i--) {
rightTop++;
leftTop--;
if(ch2[i][index]=='Q')return false;
if(rightTop<ch2.length) {
if(ch2[i][rightTop]=='Q')return false;
}
if(leftTop>=0) {
if(ch2[i][leftTop]=='Q')return false;
}
}
return true;
}
}