草庐IT

这就是传说中超难的N皇后?——详细图解!

蓝色学者i 2023-10-02 原文

✔️本文主题:回溯算法之N皇后 算法
✔️题目链接:N皇后

详解N皇后

一、前言

大家好久不见,今天我们一起来学习一道很经典、也很有难度的一道题目——N皇后

二、题目信息

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间 不能 相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。


说白了,这道题题目就是让所有皇后之间不在同一行、同一列、同一对角线,求出所有满足此要求的棋盘!

如图示,左边3X3的样例就是不符合要求的!!!我们要收集 所有 像4X4这样的样例!!!

三、解题思路

思路分析

一看到这道题目,我们会很自然想要用暴力算法来解决,例如设置一个for循环来遍历第一行、再来一个for循环遍历第二行…依此类推。

暴力算法当然是可以解决这道题目的,但这里就会有一个问题,3X3的棋盘我们套3个循环,那4X4的棋盘呢?5X5的又怎么办呢?

因此我们用暴力循环其实是不太适合这道题目的,因为我们没法控制每次套几个循环,那有没有一种方式能够让我们控制有几个for循环呢?

答案是有的!!!看过上次讲解的小伙伴应该知道,回溯算法恰好是用来实现多重for循环的一个算法,他本质上也是一个暴力算法,回溯算法基础


我们按照暴力算法的思路先来分析一下:

核心思路就是:定住第一行的一个元素,然后去下一行定住一个元素,再去下一行定住一个元素,直到底行。

画图表示:

因为图片大小原因,我只把中间过程的某一步完全画了出来,大家明白暴力算法的思路即可。


那么怎么实现我们这个 可变for循环 呢,是的,就是使用 回溯算法

之前说过,回溯算法本质也是暴力算法,他通过递归的方式来实现多重for循环,从而解决暴力算法无法设计多重循环的问题,那按照回溯算法的基本思路,我们一起来设计一下!!

✔️递归终止条件

什么时候棋盘放下了所有皇后,什么时候就停止递归,啥时候所有皇后都放下了?当然是最后一层for循环也走完了的时候。

这里我再简单补充一句:为什么是for循环走完才证明皇后全都放下了?之前放完皇后不行吗

不要忘记规则的约束,同一行或同一列或同一斜线上的皇后会相互攻击,如果你把两个皇后放到同一行,直接就不符合规则了,因此一行放且必须放一个!!!

✔️每一层的处理逻辑

如果不在最终层,我们就要用递归的思路去实现多重for循环!

for(int i=0;i<n;i++)
{
	chessboard[row][rol] = 'Q'; //确定好这一层的一个皇后
	backtracking();//递归此函数,继续向下执行相同逻辑
	chessboard[row][rol] = '.'; //将刚刚确定好的皇后剔除,换成下一个
	
}

固定好一个元素,要去递归执行下一层了,当满足收集结果的条件后,递归结束,再将棋盘上的皇后剔除,固定下一个元素继续执行相同的逻辑。

能够跳回原来的状态,这就是回溯算法的精髓。

✔️收集结果

当我们进入最终层,就要准备收集结果了,并非所有棋盘都需要收集,我们只需要收集 满足 皇后同一行或同一列或同一斜线上 的棋盘,因此我们需要判断棋盘是否符合要求!

但要把所有情况都算出再来检查就会产生大量时间浪费和代码冗余,因此我们采用放皇后时,就检查棋盘是否符合要求,如果不符合,直接进行下一次循环!

要检查当前位置可不可以放置皇后,需要满足三个条件

针对以上三种情况,我们写一个简单函数:

bool CheckBoard(vector<string>& chessboard,int row,int col,int n)
{
	//此函数判断第row行第rol列能不能放皇后

	//同一列
	for (int i = 0;i<row;i++)
	{
		if (chessboard[i][col] == 'Q')
		{
			return false;
		}
	}

	//45°
	for (int i = row - 1, j = col + 1; i >= 0 && j < n ;i--,j++)
	{
		if (chessboard[i][j] == 'Q')
		{
			return false;
		}
	}

	//135°
	for (int i = row-1,j = col-1;i>=0 && j>=0;i--,j--)
	{
		if (chessboard[i][j] == 'Q')
		{
			return false;
		}
	}

	return true;

}

四、参考代码

class Solution {
public:
    vector<vector<string>> result;
    void backtracking(int n, int row, vector<string>& chessboard) 
    {
        if (row == n) 
        {
            result.push_back(chessboard);
            //收集合法的结果,只有合法才能来到最后!!!
            return;
        }
        for (int col = 0; col < n; col++) //行固定了,列开始回溯!!
        {
            if (CheckBoard(chessboard,row, col, n)) 
            { 
                // 验证合法就可以放
                chessboard[row][col] = 'Q'; // 放置
                backtracking(n, row + 1, chessboard);//去遍历下一层!!
                chessboard[row][col] = '.'; // 撤销
            }
        }
    }
    bool CheckBoard(vector<string>& chessboard,int row,int col,int n)
    {
        //此函数判断第row行第rol列能不能放皇后

        //同一列
        for (int i = 0;i<row;i++)
        {
            if (chessboard[i][col] == 'Q')
            {
                return false;
            }
        }

        //45°
        for (int i = row - 1, j = col + 1; i >= 0 && j < n ;i--,j++)
        {
            if (chessboard[i][j] == 'Q')
            {
                return false;
            }
        }

        //135°
        for (int i = row-1,j = col-1;i>=0 && j>=0;i--,j--)
        {
            if (chessboard[i][j] == 'Q')
            {
                return false;
            }
        }

        return true;
    }
    vector<vector<string>> solveNQueens(int n) 
    {
        vector<string> chessboard(n, string(n, '.'));
        backtracking(n, 0, chessboard);
        return result;
    }
};

五、结语

回溯算法是一种很神奇的算法,他能通过递归来实现多重for循环,从而将复杂的问题解除,虽然本质上他还是暴力算法,但对于全排列、N皇后这类问题,能解出答案就已经很不错了~

如果你感觉有所收获,可以点赞 + 收藏 +关注 支持一下蓝色学者哦~ 我们下次见~

有关这就是传说中超难的N皇后?——详细图解!的更多相关文章

  1. 在VMware16虚拟机安装Ubuntu详细教程 - 2

    在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主

  2. 100个python算法超详细讲解:画直线 - 2

    1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva

  3. H2数据库配置及相关使用方式一站式介绍(极为详细并整理官方文档) - 2

    目录H2数据库入门以及实际开发时的使用1.H2数据库的初识1.1H2数据库介绍1.2为什么要使用嵌入式数据库?1.3嵌入式数据库对比1.3.1性能对比1.4技术选型思考2.H2数据库实战2.1H2数据库下载搭建以及部署2.1.1H2数据库的下载2.1.2数据库启动2.1.2.1windows系统可以在bin目录下执行h2.bat2.1.2.2同理可以通过cmd直接使用命令进行启动:2.1.2.3启动后控制台页面:2.1.3spring整合H2数据库2.1.3.1引入依赖文件2.1.4数据库通过file模式实际保存数据的位置2.2H2数据库操作2.2.1Mysql兼容模式2.2.2Mysql模式

  4. 华为ensp详细安装包、安装教程及所遇问题 - 2

    目录一、安装包链接二、安装详细步骤1.安装Wireshark和WinPcap2.安装OracleVMVirtualBox3.安装ensp三、安装后注册四、启动路由器出现40错误怎么解决一、安装包链接二、安装详细步骤链接:https://pan.baidu.com/s/1QbUUYMOMIV2oeIKHWP1SpA?pwd=xftx提取码:xftx1.安装Wireshark和WinPcap找到Wireshark安装包所在文件夹,双击它,按照以下步骤安装。2.安装OracleVMVirtualBox找到OracleVMVirtualBox安装包所在文件夹,双击它,按照以下步骤安装。注:可自定义安装

  5. Linux操作系统CentOS7安装Nginx[详细版] - 2

    Nginx安装1.官网下载Nginx2.使用XShell和Xftp将压缩包上传到Linux虚拟机中3.解压文件nginx-1.20.2.tar.gz4.配置nginx5.启动nginx6.拓展(修改端口和常用命令)(一)修改nginx端口(二)常用命令1.官网下载Nginxhttp://nginx.org/en/download.html这里我下载的是1.20.2版本,大家按需下载对应稳定版即可2.使用XShell和Xftp将压缩包上传到Linux虚拟机中没有XShell可以参考《Linux操作系统CentOS7连接XShell》3.解压文件nginx-1.20.2.tar.gz1)检查是否存

  6. Anaconda3、TensorFlow和keras简单安装方法(较详细) - 2

    因学习需要用到keras,通过查找较多资料最终完成Anaconda、TensorFlow和Keras的简单安装。因为网上的相关资料较多但大部分不够全面,查找起来不太方便,因此自己记录一下成功下载安装的详细过程,顺便推荐一下借鉴的写的很好的相关教程文章。keras需要在TensorFlow之上才能运行,所以要先安装TensorFlow,而TensorFlow只能在3.7以前的python版本中运行,所以需要先创建一个基于python3.6的虚拟环境,因此便需要先下载Anaconda。一、Anaconda3下载和安装Anaconda下载安装教程原文链接:https://blog.csdn.net/

  7. 【动态规划】背包问题(详细总结,很全) - 2

    【动态规划】一、背包问题1.背包问题总结1)动规四部曲:2)递推公式总结:3)遍历顺序总结:2.01背包1)二维dp数组代码实现2)一维dp数组代码实现3.完全背包代码实现4.多重背包代码实现一、背包问题1.背包问题总结暴力的解法是指数级别的时间复杂度。进而才需要动态规划的解法来进行优化!背包问题是动态规划(DynamicPlanning)里的非常重要的一部分,关于几种常见的背包,其关系如下:在解决背包问题的时候,我们通常都是按照如下五部来逐步分析,把这五部都搞透了,算是对动规来理解深入了。1)动规四部曲:(1)确定dp数组及其下标的含义(2)确定递推公式(3)dp数组的初始化(4)确定遍历顺

  8. 一文让你彻底掌握操作符(超详细教程) - 2

    ✅作者简介:大家好,我是小杨📃个人主页:「小杨」的csdn博客🔥系列专栏:小杨带你玩转C语言【初阶】🐳希望大家多多支持🥰一起进步呀!大家好呀!我是小杨。小杨花几天的时间将C语言中的操作符这部分知识做了一个大总结,在方便自己复习的同时也能够帮助到大家。通篇字数在一万字左右,可以算作是非常详细了,一文就可以带领大家彻底掌握操作符这部分内容,文章很长建议先收藏再看,防止下次想看就找不到啦。文章目录✍1,算术操作符✍2,移位操作符    🔍2.1,左移操作符    🔍2.2,右移操作符       ✨2.2.1,算术移位       ✨2.2.2,逻辑移位✍3,位操作符    🔍3.1,按位与&   

  9. nginx配置https后报错nginx: [emerg] https protocol requires SSL support in XXX.conf详细解决方法 - 2

    一、前言最近,在测试环境的nginx里增加了一个https配置:location/api-meeting-qq/{proxy_passhttps://api.meeting.qq.com/;}然后,执行命令://这个是nginx启动文件的路径,根据实际情况自行更改sudo/home/useradmin/nginx/sbin/nginx-sreload结果,nginx就报错了:nginx:[emerg]httpsprotocolrequiresSSLsupportin/home/useradmin/nginx/conf.d/trainNginx.conf:9二、解决方法百度发现,是之前安装ngi

  10. ruby-on-rails - 自动删除 Amazon S3 中超过 n 天的对象(如何?) - 2

    我在AmazonS3中存储了很多图像,使用ruby库(http://amazon.rubyforge.org/)我不关心超过1周的照片,然后为了释放S3中的空间我必须删除这些照片。我知道有一种方法可以删除某个桶中的对象:S3Object.delete'photo-1.jpg','photos'有没有办法自动删除一周前的图片?如果它不存在,我将不得不编写一个守护进程来做到这一点:-(谢谢更新:现在可以了,查看Roberto的回答。 最佳答案 您可以使用AmazonS3对象过期策略AmazonS3-ObjectExpiration|AW

随机推荐