所谓八皇后问题就是:将八位皇后放在一张8x8的棋盘上,使得每位皇后都无法吃掉别的皇后,(即任意两个皇后都不在同一条横线,竖线和斜线上),问一共有多少种摆法。?
下面是一个皇后和两个皇后封锁的所有区域
继续下去后面的皇后可白放的位置越来越少,那么怎么能完全的把这八个皇后放进去呢,
简单分析问题来看就是你第一行放第一个然后第二行再放第二个以此类推,如果不行那么就继续换上一行,上一行不行再上一行,以此类推,问题解决是能解决,那么能找到所有的解吗,显然是不可能的,运算次数已经超出了我们的范围。
那我们不妨来回溯一下汉诺塔,汉诺塔也是运用到次种思想(递归)
开始我们往下递如果我们没有到第8层之前就已经无法摆放的情况,我们只能往上归,移动上层的皇后看是否能摆,如果能的话那么就进行下一层,以此类推。
八皇后问题也可以看成四皇后
1.绿颜色的是皇后 黑色的是不能放皇后
2.放到第二个皇后就发现第三个皇后没办法放 那就只能退回第二行重新放
3.第四个皇后没位置了
4.把第一个皇后往后放 然后这是其中一种摆法
这也就是递归的思想
在代码中怎样实现这样的思想呢?
第一次进来,横角标等于0,意思是要在第一行摆皇后,只要传进来的角标不是8,表明还没出结果,就都不会走if里面的return,那么就进入到for循环里面,纵角标从0开始,即第一列。此时第一行第一列肯定符合要求,能放下皇后,因为还没有任何其他皇后来干扰。
关键是check方法通过了之后,在if里面又会调用一下自己(即递归),角标加了1,表示摆第二行的皇后了。第二行的皇后在走for循环的时候,分两种情况,第一种情况:for循环没走到头时就有通过check方法的了,那么这样就顺理成章地往下走再调用一下自己(即再往下递归),角标再加1(即摆第三行的皇后了,以此类推)。第二种情况:for循环走到头了都没有通过check方法的,说明第二行根本一个皇后都摆不了,也递归不了,下面的第三行等等后面的就更不用提了,此时控制第一行皇后位置的for循环纵角标加1,即第一行的皇后往后挪一格,即摆在第一行第二列的位置上,然后再往下走,重复上述逻辑。
代码如下
import java.util.*;
class eight{
public static int[][] arry=new int[8][8];//棋盘,放皇后
public static int map=0;//存储方案结果数量
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("八皇后问题");
findQueen(0);
System.out.println("八皇后问题共有:"+map+"种可能");
}
public static void findQueen(int i){//寻找皇后节点
if(i>7){ //八皇后的解
map++;
print();//打印八皇后的解
return;
}
for(int m=0;m<8;m++){//深度回溯,递归算法
if(check(i,m)){//检查皇后摆放是否合适
arry[i][m]=1;
findQueen(i+1);
arry[i][m]=0;//清零,
}
}
}
public static boolean check(int k,int j){//判断节点是否合适
for(int i=0;i<8;i++){//检查行列冲突
if(arry[i][j]==1){
return false;
}
}
for(int i=k-1,m=j-1; i>=0 && m>=0; i--,m--){//检查左对角线
if(arry[i][m]==1){
return false;
}
}
for(int i=k-1,m=j+1; i>=0 && m<=7; i--,m++){//检查右对角线
if(arry[i][m]==1){
return false;
}
}
return true;
}
public static void print(){//打印结果
System.out.print("方案"+map+":"+"\n");
for(int i=0;i<8;i++){
for(int m=0;m<8;m++){
if(arry[i][m]==1){
//System.out.print("皇后"+(i+1)+"在第"+i+"行,第"+m+"列\t");
System.out.print("o ");
}
else{
System.out.print("+ ");
}
}
System.out.println();
}
System.out.println();
}
}
执行结果: