一文搞懂数据结构之 递归-八皇后问题

2021/8/6 23:09:43

本文主要是介绍一文搞懂数据结构之 递归-八皇后问题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

八皇后是一个经典的递归问题,为了加深对八皇后解题思路的理解,故写此笔记

首先,了解一下八皇后问题:

八皇后问题(英文:Eight queens),是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出的问题,是回溯算法的典型案例。 问题表述为:在8×8格的国际象棋上摆放8皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 

根据八皇后问题提取八皇后摆放条件

1. 任意皇后不能在同一列

2.任意皇后不能在同一行

3. 任意皇后不能在同一斜线

画图理解:

        

肉眼观察,在同一行,同一列的好判断,那么在同一斜线上的怎么判断呢,这里再来看一个图

 可以看到,蓝皇后和绿皇后在同一斜线上,和红皇后也在同一斜线上,

通过观察,可以发现,蓝皇后到绿皇后的横向距离纵向距离相等,都是3 ,而到红皇后的横纵距离也相等是1。不难发现,蓝皇后到到红绿皇后的横纵距离分别相等,而那条斜线,他的斜率是1 或-1,根据计算蓝皇后和每个皇后的斜率,只要不是1 或-1 再加上条件 不在同一行,同一列,我们就可以知道这个皇后的摆放位置是否符合规则。

 

 

 总结条件:【1. 不在同一行 | 2. 不在同一列 | 3. 和已放置的皇后的斜率不等一 1 或 -1 即 绝对值不等一1 】

 整个回溯求解过程中,最难理解的可能就是皇后的斜边冲突问题。

求解约定:

        定义一个一维数组去作为棋盘

        一维数组的下标是棋盘的行,一维数组的值表示皇后放在该行的第几列

        假如 arr[0] = 0    下标是0  值是 0 就是棋盘的第1行,第一列,就是第1个黑皇后的位置

        假如 arr[1] = 2     下标是1 值是 2 就是棋盘的第2行,第3列  ,就是第2个绿皇后的位置

        假如 arr[3] = 6     下标是3 值是 6 就是棋盘的第4行,第7列  ,就是第4个红皇后的位置

         .......

        

 那么,判断第 n 和皇后位置摆放是否符合规则的条件就是

        第 n 个皇后所在的列和已放置的皇后不在同一列,  arr[i] != arr[n]  i 取值 [0,n)

        第 n 个皇后和已放置皇后的横向距离 != 纵向距离 即 (n-i) != | arr[n] - arr[i] |

      (n-i) 是纵向距离,即隔了多少行,

       而,arr[n] 是第n 个皇后所在的列,arr[i] 是第 i 个皇后所在的列

       所以  | arr[n] - arr[i] | 即第n个皇后 和第 i 个皇后的列距离的绝对值

        

 

 

求解八皇后代码:注释很全

package pers.uxteam.data;
/*
* 约定: 用一个一维数组表示八皇后棋盘,
*       八皇后棋盘一共 8 行 8 列 范围是[0,7]
*       那么,一维数组的下表表示棋盘的行,
*       一维数组的值表示皇后所在的列 取值范围 [0,7]
*       例如 :int[] map = [4, 2, 0, 5, 7, 1, 3, 6]
*       map[0] = 4   //  表示在棋盘的第 0 行,第 4 列 是第一个皇后的摆放位置
*       map[1] = 2   //  表示在棋盘的第 1 行,第 2 列 是第一个皇后的摆放位置
*       map[3] = 0   //  表示在棋盘的第 3 行,第 0 列 是第一个皇后的摆放位置
*       .......
*
[0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 0]
[0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0]
* */

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Queue8 {
    private int max = 8; // 定义八行八列
    private int[] chess = new int[max];
    // 放置第 n 个皇后
    public void layon(int n){
        // 如果放到了第 max 个皇后,就结束迭代
        if (n == max){
            // 可以打印 chess 观察皇后摆放
            show();
            return;
        }
        // 放置 n 个皇后
        for (int i = 0; i < max; i++){ // 这个循环的意义是,皇后放在第 i 列是否合适
            chess[n] = i; // 放到这一列
            if (isRight(n)){ // 检测放到这一列,皇位是否安稳
                // 如果可以,就继续迭代,去放 下一个皇后 n + 1
                layon(n+1);
            }
            // 否则继续循环,放置到其他列
        }
    }
    // 判断第n个皇后的位置是否和其他皇后冲突
    public boolean isRight(int n){
        // 根据约定,我们知道,在摆放第 n 个皇后时,不能和其他皇后在同一列,
        // 也就是数组的值不相同,这是第一个条件
        // 每个皇后都不能在同一斜线上,也就是皇后到皇后之间的行和列距离不能相等,
        // 不然就是正方形,,那么这条斜线的斜率要么是1,要么是-1 可以使用绝对值化,
        // 判断行列距离是否相等。
        // 和前面 的皇后比较是否冲突,当我们摆放 第 n 个皇后时,前面已经有了 n -1 个皇后
        // 每个都要判断
        for (int i = 0;i<n;i++){
            if (chess[i] == chess[n] || Math.abs(n-i) == Math.abs(chess[n] - chess[i])){
                // 冲突
                return false;
            }
        }

        return true;
    }
    public void show(){
        int[][] chess = new int[max][max];
        // 将一维数组恢复成二维数组打印
        for (int i = 0; i< max; i++){
            chess[i][this.chess[i]] = 1;
        }
        for (int[] row : chess){
            // 打印每一行
            List<Integer> collect = Arrays.stream(row).boxed().collect(Collectors.toList());
            System.out.println(collect);
        }
    }
}

 

 

 



这篇关于一文搞懂数据结构之 递归-八皇后问题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程