八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

java 八皇后 回溯算法 java八皇后问题_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;
	}

}