import java.util.Scanner;
/**
皇后是国际象棋中威力最大的棋子。在下面所示的棋盘上,皇后可以攻击位于箭头所覆盖位置的所有棋子。
我们能不能把N个皇后放在棋盘(N×N)上,它们中的任何一个都无法攻击其余的皇后,即任两个皇后不能在同一行,同一列或者同一对角线上。
请编写程序输出皇后的摆放方案,并找出一共有几种方法。
* @author Vivinia
*
*/
public class NQueen {
static int count=0;
static int N=0;
static int[][] Q;
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
N=input.nextInt();
Q=new int[N][N];
input.close();
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
Q[i][j]=0;
Queen(0); //从第1行开始,放第一个皇后
System.out.println("The number of the answer are "+count);
}
private static void Queen(int k) {
if(k==N) { //递归结束
for(int i=0;i<N;i++) {
for(int j=0;j<N;j++)
System.out.print(Q[i][j]+" ");
System.out.println();
}
System.out.println();
count++;
return; //这也是退出的一种方式,所以不管找到没找到解,都要回溯进行下一次查找
}
for(int j=0;j<N;j++) { //4个皇后乃没有放完
if (isCorrect(k,j)) { //如果Q[i][k]可以放 皇后
Q[k][j]=1; //放皇后
Queen(k+1); //递归检索下一行的位置
Q[k][j]=0; //回溯到上一层(如果下一行没有找到合适的位置,则执行完退回执行该语句,如果找到合适的点,会一直递归,知道找到解)
}
}
}
private static boolean isCorrect(int i, int j) { //判断行,列,两条对角线
int s,t;
for(s=i,t=0;t<N;t++) //判断行
if(Q[s][t]==1&&t!=j)
return false;
for(t=j,s=0;s<N;s++) //判断列
if(Q[s][t]==1&&s!=i)
return false;
for(s=i-1,t=j-1;s>=0&&t>=0;s--,t--) //判断左上方
if(Q[s][t]==1)
return false;
for(s=i-1,t=j+1;s>=0&&t<N;s--,t++) //判断右上方
if(Q[s][t]==1)
return false;
return true;
}
}
之前曾经N皇后的例子,但那是根据老师的算法写的,感觉思路不是很清晰。今天修改了判断部分的代码,可能比之前那个繁琐了些,但是我觉得更容易理解。
回溯之类的算法我一直不怎么会用,通过这个例子我才似乎明白了,不需要额外设置什么变量保存上一个放皇后的位置,因为回溯是基于递归的,而递归都是通过栈来实现的,所以当你重新递归一次时,会在栈中保存你当前的变量。到最后不管你是查询失败return的还是查询成功return的,都会重新回到这个位置取出栈中元素。