回溯法解决八皇后问题
一、八皇后问题简介
八皇后问题,一个古老而著名的问题,是回溯算法的典型案例。该问题由国际西洋棋棋手马克斯·贝瑟尔于 1848 年提出:在 8×8 格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有 76 种方案。1854 年在柏林的象棋杂志上不同的作者发表了 40 种不同的解,后来有人用图论的方法解出 92 种结果。
如下图是它的一种解法
二、解决思路
采用递归回溯的方法解决。
先做如下约定
- 我们用ways[8],这个数组存储摆放皇后的方式,其中,下标表示第几行,对应的值表示皇后所在的列
- judge(int n) 表示判断正在放置的第n个皇后,是否会与之前摆放好的皇后存在列冲突与对角线冲突(默认皇后不摆放在一行)
- putQueen(int n) 该方法为递归的调用放置皇后的方法,若出现冲突则回溯。
具体步骤:
- 先在第一行第一列放置第一个皇后,然后,再第二行放置第二个皇后,若与现有皇后站位不冲突,则继续在第三行放置第三个皇后......
- 如果发现冲突,则调整列,直到所有列均试完,若发现可以放置,则继续放置下一行,直至八个皇后均摆放完毕,如果,所有的列均与现有皇后的站位冲突则,回溯至上一行,继续遍历上一行的各列,以此类推,直到将第一行的各列均遍历完毕,就得到所有的结果。
三、代码实现
/**
* @author ymy
* @date 2020/5/12
*
* 八皇后问题:
* 在8*8的棋盘上,放置八个皇后,
* 要求这八个皇后的任意两个不在同一行,同一列,同一斜线
*/
public class EightQueens {
private int queenNum = 8;//皇后数量
private static int WAYS_NUM;
private int [] ways=new int [8];//放置方法
private static int judgeNums;
/**
* @param n 表示正在放置的第n个皇后
* @return
* 因为ways存储的含义就不包括同一行,所以只需要判断是否在同一列或者同一斜线即可。
*/
public boolean jugde(int n){
judgeNums++;
for (int i = 0; i <n ; i++) {
// 同一行 同一列(参考正方形对角线)
if (ways[i]==ways[n] || Math.abs(ways[i]-ways[n])==Math.abs(i-n)){
return false;
}
}
return true;
}
public void print(){
WAYS_NUM++;
System.out.printf("这是第%d种方法:",WAYS_NUM);
for (int a:ways){
System.out.print(a+" ");
}
System.out.println();
}
/**
* @param n 放置的第n个皇后
*/
public void putQueen(int n){
if (n==queenNum){
print();
return;
}
for (int i=0;i<queenNum;i++){
ways[n]=i;
if (jugde(n)){
putQueen(n+1);
}
}
}
public static void main(String[] args) {
EightQueens eightQueens = new EightQueens();
eightQueens.putQueen(0);
System.out.println("判断次数:"+judgeNums);
}
}