八皇后问题—Java—递归回溯
八皇后问题(回溯算法)
一、问题介绍:
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是由国际西洋棋手马克斯 • 贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后不能处于同一行、同一列或同一斜线上,问有多少种摆法。通过计算可以得出共有92种摆法,下面我们就对这个问题进行解决。
二、问题分析
1、通过问题的介绍,我们可以获取一些信息,即:任意两个皇后不能处于同一行、同一列或同一斜线上如图所示,蓝色实心圆表示皇后。
2、思路分析
首先我们在第一行的第一个位置摆一个皇后,因为任意皇后不能在同一行,所以我们只能在下一行摆皇后,但又必须要满足任意皇后不在同一列和同一斜线,在第二行找到满足条件的格子后摆上皇后,接着又在第三行继续找满足条件的格子、、、依次类推,直到在满足条件的情况下,将8个皇后摆完。值得注意的是,在摆到最后一个的时候,此时摆的皇后可能与前面的某个皇后冲突,这时我们就要回溯,把前一步摆的皇后重新摆,如果如此之后还是不能满足条件,那么就在往前一步、、、、这就是回溯。
3、实现
-
首先,我们需要一个数组用于存放结果,这里,选取 一维数组arr[ ] 即可;因为任意两个皇后是不可能存在同一行的情况,所以我们只需记录皇后在棋盘中的列坐标即可。一维数组的第一个值就表示棋盘中第一行皇后的列坐标,第二个值表示棋盘中第二行皇后的列坐标值,所以我们只需要一个一维数组就在足够了,相当于,一维数组的索引表示皇后在棋盘中的横坐标,索引所对应的值表示皇后在棋盘中的列坐标。
-
我们需要写一个方法来判断在摆皇后的过程中,皇后的位置是否违反了所给定的规则:即判断任意两个皇后是否在同一行,同一列或同一斜线。
判断任意两个皇后是否在同一列:前面我们给了一个arr[ ]数组来存放皇后的坐标,那么当 arr[n]==arr[i] (即:列坐标相等)时第n个皇后和第i个皇后处于同一列,违反规则。
判断任意两个皇后是否在同一斜线:
①:相邻两行的皇后处于同一斜线位置,如图2,那么其横坐标之差的绝对值等于其列坐标之差的绝对值 即:Math.abs(n - i) == Math.abs(arr[i] - arr[n])【Math.abs(x):x的绝对值】
②:不相邻的皇后处于同一斜线位置,如图3,通过图可以看出,两个皇后的横坐标之差等于 2 ,列坐标之差也等于 2 所以可以得出不相邻的皇后处于同一斜线位置时:Math.abs(n - i) == Math.abs(arr[i] - arr[n])
③:综上所述:任意两个皇后处于同一斜线时满足:其横坐标之差的绝对值等于其列坐标之差的绝对值 即:Math.abs(n - i) == Math.abs(arr[i] - arr[n])【Math.abs(x):x的绝对值】
- 有了判断任意两个皇后的位置是否合法的方法之后,还需要一个摆皇后的方法,在摆之前我们需要判断皇后是否摆完了,接着通过一个for循环一个一个的摆,在摆的过程中需判断位置是否合法。
三、代码实现
public class Quuen8 {
// 八皇后问题,在一个8×8的国际象棋棋盘上摆放8个皇后,摆放需遵守皇后不能处于同一行、同一列、同一斜线上,问有多少种摆法
int max = 8;//皇后个数
static int count = 0;//记录有多少种摆法
// 初始化一个数组用于存放结果
/*
* 这里用一维数组存放数据就可以了,这里一维数组中的值存放的是皇后的列坐标,
* 因为规定皇后是不能摆放在同一行,所以每一行只有一个皇后 ; 一维数组 arr
* 的第一个值就是 棋盘第一行皇后的列坐标值,第二个值就是皇后在棋盘第二行的列坐标值
*/
int[] arr = new int[max];
public static void main(String[] args) {
// TODO Auto-generated method stub
Quuen8 quuen = new Quuen8();
quuen.PutQuuen(0);
System.out.println("共有"+count+"种摆法");
}
//写一个摆皇后的方法
private void PutQuuen(int n) {
if(n==max) {//因为n是从0开始增加,即n=0表示放第一个皇后,当n==max时表示皇后已经摆完了
Print();
return;
}
for(int i=0;i<max;i++) {
arr[n]=i;//放置第一个皇后
if(judge(n)) {//判断皇后的位置是否冲突,不冲突继续放下一个皇后
PutQuuen(n+1);
}
}
}
// 写一个方法,判断皇后在该位置是否会引起冲突,即在同一行或同一列或同一斜线
private boolean judge(int n) {
for (int i = 0; i < n; i++) {
/*
* 1. 判断 皇后是否在同一列,只需判断皇后的列坐标是否相等即可,即arr[i] == arr[n]
* 2.判断皇后是否在同一斜线上,只需判断两个皇后的列坐标之差的绝对值与其横坐标之差的绝对值是否相等即可,
* 即Math.abs(n - i) == Math.abs(arr[i] - arr[n])
* */
if (arr[i] == arr[n] || Math.abs(n - i) == Math.abs(arr[i] - arr[n])) {
return false;//违反了规则,返回false
}
}
return true;
}
//输出
private void Print() {
// TODO Auto-generated method stub
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i] + " ");
}
count++;
System.out.println();
}
}
八皇后小游戏链接:大家可以通过这个游戏理解八皇后问题
上一篇: Java集合之List集合详细解释
下一篇: 八皇后问题-递归回溯