算法入门教程-递归(八皇后问题)

关于八皇后的介绍这里不做任何解释,想了解的可以去百度百科,本篇通过递归回溯的算法思想来实现八皇后的解法,直接入正题

八皇后问题描述

八皇后是古老而著名的算法思想,也是递归回溯的经典案例,就是在8*8的国际棋盘上摆放8个皇后,使其不能相互攻击,说白了就是任意两个皇后不能处于同一行同一列以及同一斜线上,共有多少种摆法?

image

上图中的所展示的就是其中一种摆法,我们来分析下摆放的步骤和思路:

思路分析
  • 首先来摆放第一个皇后,我们将第一个皇后摆放在第一行第一列的位置处
  • 接着来摆放第二个皇后,将第二个皇后摆放在第二行第一列,判断是否跟前一个摆放的皇后有冲突,如果冲突,后移动一个位置,直到找到合适的位置为止.
  • 接着上述的过程,摆放第三个皇后,还是从第1列开始 第二列....直到第8个皇后的放到不冲突的位置处,才算是找到了一种解法

上述就是八皇后摆放位置的大概思路,其实当我们找到一种方法时,根据上节对栈的了解,没执行一个方法就会开辟一个栈空间的特点:

  • 此刻就会回退到上一个栈,也就是我们回溯的开始,也就是第一个皇后在第一列的所有正解全部得到.
  • 接着将第一个皇后放在第2列的所有正解,其他一样重复该步骤.
  • 上述就是得到的所有的解法的总数

熟知了八皇后的思路分析,我们来进行代码实现,按照上图我们可以利用一个二维数组来描述我们的棋盘,实际不然我们可以用一维数组解决该问题,即array[8]= {2,4,7,3,0,6,1,5},其中array的下标表示第几行也就是第几个皇后,array[i] = value,其中value表示第i+1个皇后,需要我们放在第i+1行的第value+1列的位置处即可.既然一维数可以实现我们用代码来实现八皇后问题

代码实现过程
  • 首先我们来定义我们的棋盘,代码如下:
/**
 * 算法-递归回溯(八皇后问题)
 */
public class Queen8 {
//1.首先定义一个max表示共有几个皇后
int max = 8;
//2.定义一个数组,用来记录皇后所在位置的结果
int[] array = new int[max];
//3.统计次数
static int count = 0;
//4.统计judge的次数
static int judgeCount = 0;
  • 接着我们需要定义一个检验冲突的方法,代码如下:
//当我们在摆放第n个皇后时,就去检测当前摆放的皇后跟前面已经摆放好的皇后是否冲突如:摆放第3个皇后时,检测第二个和第一个皇后
/**
 *
 * @param n 表示第几个皇后
 * @return
 */
private boolean judge(int n){
    judgeCount ++;
    for (int i = 0; i < n; i++) {
        //说明
        //array[i] == array[n]表示:第n个皇后和它前面的第n-1个皇后是否在同一列
        //Math.abs(n -i) == Math.abs(array[n] -array[i])表示:第n个皇后和第i个皇后是否在一条斜线上
        //假设:n= 1时;那么表示第二个皇后放置在第2列1个位置处,array[1] = 1;
        //Math.abs(1-0)== 1; Math.abs(array[1] -array[0]) == 1;
        //注意:我们没有必要判断是否是同一行,因为n是递增的就表示当前行的皇后
        if (array[i] == array[n] || Math.abs(n -i) == Math.abs(array[n] -array[i])){
            return false;
        }
    }
    return true;

}
  • 还需要定义一个找位置的方法,代码如下:
private void check(int n){
    if (n == max){ //表示n=8也就说8个皇后都放置好了
        print();
        return;
    }
    //依次放入皇后,并判断是否冲突
    for (int i = 0; i < max; i++) {
        //先把当前皇后n放置在该行的第1列
        array[n] = i;
        //判断放置当前第n个皇后到i列时,是否冲突
        if (judge(n)){ //表示不冲突
            //接着放第n+1个皇后,这里使我们递归的开始
            check(n+1);
        }
        //这里表示冲突,如果冲突的话,继续执行我们的array[n] = i,此刻i+1,后移动一个位置
    }
}

注意:上述的方法中用到了回溯的特性,在哪体现了,当我们的方法check执行时,每一次递归都有一个for (int i = 0; i < max; i++)循环执行,因此一定会回溯到上一个栈.

  • 最后定义一个打印方法,代码如下:
//打印皇后的摆放位置
public void print(){
    count ++;
    for (int i = 0; i < array.length ; i++) {
        System.out.print(array[i] + " ");
    }
    System.out.println();
}
  • 测试代码如下:
public static void main(String[] args) {
    //测试
    Queen8 queen8 = new Queen8();
    queen8.check(0);
    System.out.printf("共计有%d中解法",count);
    System.out.println();
    System.out.printf("共计判断冲突次数为%d次",judgeCount);
    System.out.println();
}

我们来看运行结果如图:

运行结果1.png
八皇后结果图.png

上述图中的是部分结果图,我们发现共有92中解法,和1.5w次的冲突判断,其实发现回溯的效率并不是很高,那么关于八皇后的解法就到这里.

你可能感兴趣的:(算法入门教程-递归(八皇后问题))