八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。
问题分析:根据题意也就是说开始放置一个皇后在棋盘上,然后再放置一个皇后要考虑当前位置是否能放置,直到所有位置都比对过后不能放置,这就是八皇后的一种情况,假设我们现在逐个查找,从第一个开始查找,第一个位置是被允许的,然后从第二行开始查找,直到直到个满足的位置,再到第三行位置开始查找。
public class eigthQueen {
public static int count=0; //定义一个全局变量,下面会用到
public static void main(String[] args) {
// TODO Auto-generated method stub
int[][] matrix =new int[9][9];
Queen(0,matrix); //调用递归的函数是从该数组的0第一个元素开始的
}
public static void Queen(int row ,int[][] arr) {
if(row==arr.length) {//如果已经到了该数组的最后一行,说明一种情况就找完了
count++; //记录这是第几种情况,所以用到上面全部变量,因为后面要调用自身函数,
//如果在函数一开始定义一个count,那么他的值永远都是0和1,定义在主函数这里是访问不到的,所以用到全局变量
System.out.println("这是第"+count+"种情况:"); //打印出现的第几种情况
for(int i =0;i<arr.length;i++) {
for(int j=0;j<arr[i].length;j++) {
System.out.print(arr[i][j]);
}
System.out.println();
}
}else {//如果没有找到该数组的最后一行
int[][] newArr = new int[arr.length][arr[0].length];//先创建一个新的数组用来存放已经出现的结果,也就是数组里面的值,
//为什么要定义新数组的原因是在原来的数组上操作可能如果下一行的所有位置都不满足放一个皇后也没有到最后一行或是已经到最后一行,
//要查找下一种情况的时候,要往会退,所以可以直接将加载到此函数位置的函数弹栈不要,就返回了原来的数组,这样更方便
for(int i=0;i<newArr.length;i++) {
for(int j=0;j<newArr[0].length;j++) {
newArr[i][j]=arr[i][j];
}
}
for(int i=0;i<newArr.length;i++) {//从当前的行开始逐个向后判断
if(noDengours(row,i,newArr)) { //如果当前的某个位置是可以的
for(int c=0;c<newArr[0].length;c++) {//这里是用来当下一行所有位置都不能置一的时候,用来退回的
newArr[row][c]=0;
}
newArr[row][i]=1; //将此位置置为1,表示这个可以放
Queen(row+1,newArr); //然后在同样的方式找下一行的位置
}
}
}
}
public static boolean noDengours(int row,int col,int[][] arr) {//怎么判断当前位置是可以置一的,这里要传递一个要判断位置的行列和当前所在的矩阵
//先判断上面是否有没有已经置一的位置
for(int i=row-1;i>=0;i--) { //此位置的上面,列不变向上找行
if(arr[i][col]==1) { //一旦发现
return false; //此位置不能放
}
}
//在判断右上的位置是否有1
for(int i=row-1 ,j=col+1;i>=0 &&j<arr[0].length;i--,j++) { //此位置的右上方行要减1,列要加1
if(arr[i][j]==1) {
return false;
}
}
//最后判断左上的位置是否有一
for(int i =row-1,j=col-1;i>=0&&j>=0;i--,j--) { //此位置的左上方行要减一列也要减一
if(arr[i][j] ==1) {
return false;
}
}
return true;//如果都没找到,那么说明没有,此位置是可以存放的
}
}