递归求解n皇后问题的解析和求解(矩阵储存版)

这篇具有很好参考价值的文章主要介绍了递归求解n皇后问题的解析和求解(矩阵储存版)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

递归求解n皇后问题的解析和求解(矩阵储存版)

1. n皇后问题问题描述

​ n皇后问题来源于著名的十九世纪著名数学家提出的八皇后问题。问题为:在8×8的棋盘上摆放八个皇后,皇后之间不能互相攻击,既任意两个皇后不在同一行、同一列,也不再同一斜线上。n皇后则是在八皇后的基础上,将棋盘扩充为n×n,皇后的数量也相应改变为n。

递归求解n皇后问题的解析和求解(矩阵储存版),矩阵,java,线性代数

2. 利用递归与回溯求解n皇后问题

2.1递归算法

​ n皇后问题是经典的学习递归算法的经典问题。递归算法是将一种直接或者间接调用自身,将问题分解为同类子问题,从而实现复杂问题求解的一种算法。

​ 递归算法的设计重点有两点:

​ ① 分析问题, 得出递归关系。

​ ② 设置边界条件, 既控制递归出口。

2.2 回溯

​ 回溯算法是指,当对问题进行搜索尝试时,当发现 条件不符合求解条件时,则"回溯"返回,返回到上一步,继续搜索其他路径。

2.3 利用递归和回溯求解n皇后问题

​ 在对问题进行计算机求解时,我们先以四皇后问题为例,以人的思维对四皇后问题进行求解。求解过程如下图:

递归求解n皇后问题的解析和求解(矩阵储存版),矩阵,java,线性代数

​ 由上图,我们描述一下求解步骤:由于皇后不能处于同一行,所以我们会一行一行的确定皇后位置。在判断每行的皇后的位置时,会从该行的第一个位置开始遍历该行每个位置,判断该位置是否满足皇后不互相攻击的要求,如果满足,则暂时将皇后放在该位置。继续寻找下一行,如果顺利在最后一行找到符合条件的皇后,则找到答案。但如果出现某一行没有一个位置能够满足皇后放下,则说明目前这种皇后方法不合法,则回退上一个满足条件的皇后拿起,放在同一行中下一个满足条件的地方,如果该行仍没有满足条件的位置,则继续回退。在这样之下,便能得到一个正确的解。

​ 这样的思路,我们同样可以在程序设计上沿用。程序流程为:

① 先从第一行开始遍历,在第一行符合可以放置皇后的位置暂时放下皇后。

② 往下一行遍历,根据之前已经放置皇后的位置,判断该行是否存在可以放置皇后的位置,如果存在,则放置。继续遍历下一行,如果不存在,则退回,将上一行已放置的皇后拿起,寻找下一个可以放置的位置。

③ 反复执行①、②,知道结果输出。

根据以上流程,我们将会得到1个或0个(当n≤3时,没有解)解。那么,如果我们需要的到所有解呢,又该怎么办?其实很简单,只要我们在得到第一个解之后,将之输出,然后回退。那么我们又会重新执行①和②,得到第二个解(如果存在)。继续同样的操作,就可以得到需要的所有解。(此处可能有些难理解,多读几遍,然后自己走一遍四皇后的流程便能理解了)。

那理论存在,我们开始实践。

//在本程序中,*表示棋盘中未放置皇后的位置,$表示皇后,如下:
//        * * * * * * * $
//        * * * $ * * * *
//        $ * * * * * * *
//        * * $ * * * * *
//        * * * * * $ * *
//        * $ * * * * * *
//        * * * * * * $ *
//        * * * * $ * * *

//首先我们需要编写一个判断目前位置是否可以合法(既是否可以放置皇后的函数)
//其中nQueen数组为棋盘和当前皇后的放置情况,row和col为当前需要判断的棋盘位置
static boolean isLegal(char[][] nQueen,int row,int col){
    //如果是棋盘第一行,皇后一定合法;
    if (row == 0){
        return true;
    }else {
        //如果不是第一行,则需要通过该行之前已经确定的皇后判断是否该行是否合法
        //合法条件是,不能和已确定的皇后处于同一行或者在已确定的皇后的斜线上
        for(int i = 0; i < row; i++){
            for (int j = 0; j < nQueen.length; j++){
                //定位已确定的皇后位置
                if (nQueen[i][j] == '$'){
                    //判断是否和已确定的皇后同一列以及是否在已确定皇后的斜线上
                    if (col == j || row - i == Math.abs(col - j)){
                        return false;
                    }
                }
            }
        }
    }
    //如果遍历完该点之前所有的皇后都没有返回错误,证明该点合法
    return true;
}

​ 然后,我们开始设置递归函数,根据上述程序流程,我们知道每行只能放置一个皇后,因此得到递归出口为放置皇后的行数,当最后一行放置皇后之后,递归可以结束。并且已放置的皇后位置会影响后续皇后的放置。因此函数如下:

static boolean isSafe(int n, int n1, int []num,char[][] nQueen){
    //其中n表示目前还有多少个皇后未确定位置,num表示皇后的总数
    //如果只需要求解有一个答案,既所有皇后都找到了合法的位置,此时n==0,就return true
    //如果求解所有答案,则没每到一个答案,就输出一个答案,num+1。然后返回false,进行回退,继续寻找下一个答案。
    if (n == 0){
        num[0]++;
        print(nQueen);
        //分割开每个答案
        for (int i = 0; i < 2 * n1 - 1; i++) {
            System.out.print("-");
        }
        System.out.println();
        return false;
    }else {
        //如果所有行的皇后还没有找到,遍历改行每一个,查看符合的位置
        for (int i = 0; i < n1; i++){
            //如果符合,则暂定该点为皇后位置,然后遍历下一行
            if (isLegal(nQueen, n1-n, i)) {
                nQueen[n1-n][i] = '$';
                if (isSafe(n - 1, n1, num, nQueen)){
                    return true;
                }else {
                    //如果往下遍历后不成立,则将该点的皇后去掉
                    nQueen[n1-n][i] = '*';
                }
            }
        }
    }
    return false;
}

完整可执行代码:

package Test_Package;

import java.util.Scanner;
public class NQueen {
    //递归的经典问题。n皇后问题。
    public static void main(String[] args) {
        //首先对main函数进行处理
        //在本程序中,使用*代表棋盘,$好代表皇后位置
        Scanner sc = new Scanner(System.in);
        //n代表皇后维度
        System.out.print("Please enter number of queens: ");
        int n = sc.nextInt();
        //num代表答案总数,用数组形式便于输出
        int[] num = {0};
        //消除sc
        sc.close();

        //nQueen代表棋盘以及皇后的位置
        char[][] nQueen = new char[n][n];
        for (int i = 0; i < n; i++) {
            for (int j= 0; j < n; j++){
                nQueen[i][j] = '*';
            }
        }

        isSafe(n, n, num, nQueen);
        System.out.println();
        System.out.println("Number of solutions = " + num[0]);


    }

    //递归方法输出皇后结果以及方法个数
    static boolean isSafe(int n, int n1, int []num,char[][] nQueen){
        //其中n表示目前还有多少个皇后未确定位置,num表示皇后的总数
        //如果只需要求解有一个答案,既所有皇后都找到了合法的位置,此时n==0,就return true
        //如果求解所有答案,则没每到一个答案,就输出一个答案,num+1。然后返回false,进行回退,继续寻找下一个答案。
        if (n == 0){
            num[0]++;
            print(nQueen);
            //分割开每个答案
            for (int i = 0; i < 2 * n1 - 1; i++) {
                System.out.print("-");
            }
            System.out.println();
            return false;
        }else {
            //如果所有行的皇后还没有找到,遍历改行每一个,查看符合的位置
            for (int i = 0; i < n1; i++){
                //如果符合,则暂定该点为皇后位置,然后遍历下一行
                if (isLegal(nQueen, n1-n, i)) {
                    nQueen[n1-n][i] = '$';
                    if (isSafe(n - 1, n1, num, nQueen)){
                        return true;
                    }else {
                        //如果往下遍历后不成立,则将该点的皇后去掉
                        nQueen[n1-n][i] = '*';
                    }
                }
            }
        }
        return false;
    }

    //输出方法,为了方便打印结果缩写的方法
    static void print(char[][] nQueen){
        for (int i = 0; i < nQueen.length; i++) {
            for (int j = 0; j < nQueen.length; j++) {
                System.out.print(nQueen[i][j]+" ");
            }
            System.out.println();
        }
    }

    //通过已确定的位置判断皇后位置是否合法
    static boolean isLegal(char[][] nQueen,int row,int col){
        //如果是棋盘第一行,皇后一定合法;
        if (row == 0){
            return true;
        }else {
            //如果不是第一行,则需要通过该行之前已经确定的皇后判断是否该行是否合法
            //合法条件是,不能和已确定的皇后处于同一行或者在已确定的皇后的斜线上
            for(int i = 0; i < row; i++){
                for (int j = 0; j < nQueen.length; j++){
                    //定位已确定的皇后位置
                    if (nQueen[i][j] == '$'){
                        //判断是否和已确定的皇后同一列以及是否在已确定皇后的斜线上
                        if (col == j || row - i == Math.abs(col - j)){
                            return false;
                        }
                    }
                }
            }
        }
        //如果遍历完该点之前所有的皇后都没有返回错误,证明该点合法
        return true;
    }
}

输入:8

输出结果:

递归求解n皇后问题的解析和求解(矩阵储存版),矩阵,java,线性代数
(情况太多,截图仅截最后)文章来源地址https://www.toymoban.com/news/detail-804400.html

到了这里,关于递归求解n皇后问题的解析和求解(矩阵储存版)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 线性代数的学习和整理14: 线性方程组求解的3种方法,重点讲矩阵函数求解

    目录 0 写在前面的一些内容 0.1 学习心得: 0.2 参考其他书籍总结的知识点,对照学习 1 线性方程组求解 1.1 常见的线性方程组如下 1.2 记住常见的 矩阵函数的维数的关系 1.3  需要求解的方程组和矩阵的对应关系,需要先厘清 1.3.1 如果只需要求解x,是类 Ax=b的形式 1.3.2   如

    2024年02月05日
    浏览(59)
  • 算法与数据结构——递归算法+回溯算法——八皇后问题

    八皇后问题是一个经典的回溯算法问题,目的是在8×8的国际象棋棋盘上放置八个皇后,使得没有皇后可以互相攻击(即没有两个皇后在同一行、同一列或同一对角线上)。 回溯算法是一种解决问题的算法,它通过尝试所有可能的解决方案来解决问题。在八皇后问题中,计算

    2024年02月09日
    浏览(55)
  • 八皇后问题,秒懂递归回溯(有图详解|c语言)

    目录 👸🏻前言 👸🏻题目介绍 👸🏻引入: 👸🏻解决思路: 👸🏻理论存在,实践开始! 👸🏻难点1:如何表示对角线被占领? 👸🏻难点2:如何用递归的方法来放皇后? 👸🏻难点3:如何实现回溯? 👸🏻难点4:如何实现皇后位置的输出? 👸🏻全部代码如下: 👸

    2024年02月02日
    浏览(32)
  • Java代码解析:求解数组的小和问题

    在这篇博客中,我们将深入探讨如何使用Java解决一个有趣的问题:求解数组的小和问题。我们将首先理解问题的定义,然后逐步分析和解释给出的Java代码。 在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。例如,数组[1,3,4,2,5]的小和为1+1+3+1+1+

    2024年02月16日
    浏览(34)
  • 递归求解汉诺塔问题(超详解)

    这个问题是关于三根柱子和一些圆盘的游戏。 初始时,所有的圆盘按照从大到小的顺序叠放在一根柱子上,目标是将所有圆盘从起始柱子移动到目标柱子上,在移动过程中,要满足以下规则喵: 每次只能移动一个圆盘。 大圆盘不能放在小圆盘上。 只能通过中间柱子作为辅

    2024年02月15日
    浏览(77)
  • C语言实现求解斐波那契数列的四种方法及优化处理(递归,迭代,特殊性质公式,矩阵快速幂)

            众所周知, 斐波那契数列 是非常经典的一个数列,它的数学公式如下         为了便于观察,我们列出它的几项:0  1  1  2  3  5  8  13  21......         下面我们将介绍四种方法来用C语言计算机代码实现对斐波那契数列的求解,分别是:递归法,迭代法

    2023年04月09日
    浏览(41)
  • Java实现八皇后问题

    八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于 1848 年提出:在 8×8 格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 第一个皇后先

    2024年02月14日
    浏览(30)
  • Python处理矩阵和线性代数问题

    如未作说明,下列方法均调用自 linalg 矩阵分解 cholesky , qr ,奇异值分解 svd 求特征值 eigvals ,共轭对称阵特征值 eigvalsh(a[, UPLO]) 特征值和 特征向量 eig ,共轭对称的特征值和向量 eigh(a[, UPLO]) 特征数字 范数 norm ,迹 trace 条件数 cond ,行列式 det ,符号 slogdet 通过SVD方法求秩

    2024年02月05日
    浏览(37)
  • 矩阵运算之外积:解决线性代数问题的关键技巧

    线性代数是数学的一个分支,主要研究的是线性方程组和矩阵。线性方程组是指每个变量的方程都是线性的方程组,矩阵是一种数学结构,可以用来表示和解决线性方程组。在现实生活中,线性方程组和矩阵广泛应用于各个领域,如物理学、生物学、经济学、计算机科学等。

    2024年02月21日
    浏览(43)
  • 矩阵最小二乘法问题求解

    超定方程组是指方程个数大于未知量个数的方程组。对于方程组 A x = b Ax=b A x = b , A A A 为n×m矩阵,如果R列满秩,且nm。则方程组没有精确解,此时称方程组为超定方程组。 在实验数据处理和曲线拟合问题中,求解超定方程组非常普遍。比较常用的方法是 最小二乘法 。 如果

    2024年02月05日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包