回溯 皇后 算法笔记_回溯算法:N皇后问题
❝
通知:我将公众号文章和学习相关的资料整理到了Github :https://github.com/youngyangyang04/leetcode-master,方便大家在电脑上学习,可以fork到自己仓库,顺便也给个star支持一波吧!
❞
如果对回溯法理论还不清楚的同学,可以先看这个视频:
第51题. N皇后
题目链接:https://leetcode-cn.com/problems/n-queens/
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
示例: 输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
提示:
皇后,是国际象棋中的棋子,意味着国王的妻子。皇后只做一件事,那就是“吃子”。当她遇见可以吃的棋子时,就迅速冲上去吃掉棋子。当然,她横、竖、斜都可走一到七步,可进可退。(引用自 百度百科 - 皇后 )
思路
都知道n皇后问题是回溯算法解决的经典问题,但是用回溯解决多了组合、切割、子集、排列问题之后,遇到这种二位矩阵还会有点不知所措。
首先来看一下皇后们的约束条件:
- 不能同行
- 不能同列
- 不能同斜线
确定完约束条件,来看看究竟要怎么去搜索皇后们的位置,其实搜索皇后的位置,可以抽象为一棵树。
下面我用一个3 * 3 的棋牌,将搜索过程抽象为一颗树,如图:
从图中,可以看出,二维矩阵中矩阵的高就是这颗树的高度,矩阵的宽就是树型结构中每一个节点的宽度。
那么我们用皇后们的约束条件,来回溯搜索这颗树,「只要搜索到了树的叶子节点,说明就找到了皇后们的合理位置了」。
回溯三部曲
按照我总结的如下回溯模板,我们来依次分析:
void backtracking(参数) { if (终止条件) { 存放结果; return; } for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) { 处理节点; backtracking(路径,选择列表); // 递归 回溯,撤销处理结果 }}
- 递归函数参数
我依然是定义全局变量二维数组result来记录最终结果。
参数n是棋牌的大小,然后用row来记录当前遍历到棋盘的第几层了。
代码如下:
vector> result;void backtracking(int n, int row, vector& chessboard) {
- 递归终止条件
在如下树形结构中:
可以看出,当递归到棋盘最底层(也就是叶子节点)的时候,就可以收集结果并返回了。
代码如下:
if (row == n) { result.push_back(chessboard); return;}
- 单层搜索的逻辑
递归深度就是row控制棋盘的行,每一层里for循环的col控制棋盘的列,一行一列,确定了放置皇后的位置。
每次都是要从新的一行的起始位置开始搜,所以都是从0开始。
代码如下:
for (int col = 0; col if (isValid(row, col, chessboard, n)) { // 验证合法就可以放 chessboard[row][col] = 'Q'; // 放置皇后 backtracking(n, row + 1, chessboard); chessboard[row][col] = '.'; // 回溯,撤销皇后 }}
- 验证棋牌是否合法
按照如下标准去重:
- 不能同行
- 不能同列
- 不能同斜线 (45度和135度角)
代码如下:
bool isValid(int row, int col, vector& chessboard, int n) { int count = 0; // 检查列for (int i = 0; i if (chessboard[i][col] == 'Q') {return false; } } // 检查 45度角是否有皇后for (int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--) {if (chessboard[i][j] == 'Q') {return false; } } // 检查 135度角是否有皇后for(int i = row - 1, j = col + 1; i >= 0 && j if (chessboard[i][j] == 'Q') {return false; } }return true;}
在这份代码中,细心的同学可以发现为什么没有在同行进行检查呢?
因为在单层搜索的过程中,每一层递归,只会选for循环(也就是同一行)里的一个元素,所以不用去重了。
那么按照这个模板不难写出如下代码:
C++代码
class Solution {private:vector> result;// n 为输入的棋盘大小// row 是当前递归到棋牌的第几行了void backtracking(int n, int row, vector& chessboard) {if (row == n) { result.push_back(chessboard);return; }for (int col = 0; col if (isValid(row, col, chessboard, n)) { // 验证合法就可以放 chessboard[row][col] = 'Q'; // 放置皇后 backtracking(n, row + 1, chessboard); chessboard[row][col] = '.'; // 回溯,撤销皇后 } }}bool isValid(int row, int col, vector& chessboard, int n) { int count = 0; // 检查列for (int i = 0; i if (chessboard[i][col] == 'Q') {return false; } } // 检查 45度角是否有皇后for (int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--) {if (chessboard[i][j] == 'Q') {return false; } } // 检查 135度角是否有皇后for(int i = row - 1, j = col + 1; i >= 0 && j if (chessboard[i][j] == 'Q') {return false; } }return true;}public: vector> solveNQueens(int n) { result.clear(); std::vector<:string> chessboard(n, std::string(n, '.')); backtracking(n, 0, chessboard);return result; }};
可以看出,除了验证棋盘合法性的代码,省下来部分就是按照回溯法模板来的。
总结
本题是我们解决棋盘问题的第一道题目。
如果从来没有接触过N皇后问题的同学看着这样的题会感觉无从下手,可能知道要用回溯法,但也不知道该怎么去搜。
「这里我明确给出了棋盘的宽度就是for循环的长度,递归的深度就是棋盘的高度,这样就可以套进回溯法的模板里了」。
大家可以在仔细体会体会!
就酱,如果感觉「代码随想录」干货满满,就分享给身边的朋友同学吧,他们可能也需要!
打算从头开始打卡的录友,可以在「算法汇总」这里找到历史文章,很多录友都在从头打卡,你并不孤单!
-------end-------
另外因为公众号改版,时间线被打乱,一些精彩文章大家可能错过了。如果感觉这里的文章对你有帮助,赶紧给「代码随想录」加一个星标吧,方便第一时间阅读文章。「代码随想录」期待你的关注!
每天8:35准时推送一道经典算法题目,推送的每道题目都不是孤立的,而是由浅入深,环环相扣,帮你梳理算法知识脉络,轻松学算法!
刷题可以加我微信!右边为个人微信,添加时备注:「简单自我介绍」+「组队刷题」我就知道你[在看]
回溯 皇后 算法笔记_回溯算法:N皇后问题相关推荐
- 算法笔记之hoorspool算法
算法笔记之hoorspool算法 从右往左进行字符扫描,如果所有匹配成功,则找到了匹配的字串,如果遇到不匹配的时候,就需要将模式右移动,这个时候考虑的是文本与模式最后一个字符对齐的文本字符C 当字符不 ...
- 回溯 皇后 算法笔记_什么叫回溯算法,一看就会,一写就废
什么叫回溯算法 对于回溯算法的定义,百度百科上是这样描述的:回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就"回溯"返回, ...
- 算法笔记之回溯法(2)
着色问题 问题分析 假设地图共有7个区域,分别是A/B/C/D/E/F/G,对上面顺序进行编号,每个区域用一个结点表示,相邻的区域有连线,那么地图就转化成一个无向连接图. 算法设计 定义问题的解空间. ...
- 算法笔记之回溯法(一)——溯洄从之,道阻且长;溯游从之,宛在水中央。
回溯法理论基础 回溯法是一种搜索算法,从本质上来说,回溯法是一种穷举法,穷尽其所有可能而举其可行解:尽管回溯法有剪枝等操作,但也只是去除一些明显不可行的部分,仍改变不了回溯法暴力搜索的本质. 虽然回溯 ...
- 0027算法笔记——【回溯法】回溯法与装载问题
1.回溯法 (1)描述:回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法. (2)原 ...
- LQ训练营(C++)学习笔记_枚举算法
枚举算法 一.枚举算法 1.枚举的概念 2.枚举的题目特点 3.问题描述 4.代码实现 一.枚举算法 1.枚举的概念 枚举就是根据提出的问题,列出该问题所有可能的解,并在逐一列出的过程中,检验每个可能 ...
- 迪杰斯特拉算法c++_《算法图解》学习记录7--迪杰斯特拉算法
本章内容 继续图的讨论,介绍加权图--提高或降低某些边的权重. 介绍狄克斯特拉dijstra算法,让你能够找出加权图中前往X的最短路径. 介绍图中的环,它导致狄克斯特拉算法不管用. 在前一 ...
- 【数据结构和算法笔记】KMP算法介绍
BF暴力算法: 当模式串位i与目标串i比较时两字符不相等,则i的移动方式:i=i-j+1 j的移动方式:j=0 KMP算法简介: ●KMP模式匹配中,当模式串位j与目标串位i比较两字符不相等 i ...
- python贪心算法最短路径_贪心算法---最短路径问题
一,贪心算法的设计思想 • 从问题的某一个初始解出发逐步逼近给定的目标,每一步都作一个不可回溯的决策,尽可能地求得最好的解.当达到某算法中的某一步不需要再继续前进时,算法停止. 二,贪心算法的基本性质 ...
最新文章
- 统计数列中是连续数的个数
- jQuery获取CSS样式中的颜色值的问题,不同浏览器格式不同怎么办
- 【Maven】maven 插件开发实战
- 是是非非本寻常,我们要不要跳槽。
- 判断非负整数是否是3的倍数_二、因数与倍数教案
- 标题:浅析图卷积神经网络
- 2019.01.22【NOIP普及组】模拟赛C组总结
- 前端学习(803):字符串拼接和截取
- POJ3420 Quad Tiling(模板+矩阵快速幂)
- boost学习之BOOST_PP_REPEAT
- 集合竞价如何买入_世界上最稳健的抓涨停方法“10分钟集合竞价”选股诀窍,买入直接稳赚10个点,赚到笑...
- CSS属性:display详解
- 【Django 2021年最新版教程4】为项目添加资源文件(css,js,image)
- 第八课 实战重启验证注册机制
- 多线程抓取链家网数据
- call_user_func_array函数详解
- 深度相机原理及坐标系转换
- 使用if判断用户名和密码是否正确
- QT 代码行统计工具
- 5.20爬虫结——Mu
热门文章
- 活久见!谷歌开源“大杀器”,CV、NLP都能用!
- 再见吧,996!程序员开源考公指南获高赞:三人已成功上岸
- 图文并茂!60页PPT《快速入门python数据分析路线》(附链接)
- 2400门课:MIT 开放迄今最全 计算机+电气工程课程
- 全网最火的Nacos源码构建,你找不到第二个有我仔细的!!
- 打印零与奇偶数(多线程)
- Python与redis集群进行交互操作
- ACMNO.13求Sn=1!+2!+3!+4!+5!+…+n!之值,其中n是一个数字。 输入 n 输出 和 样例输入 5 样例输出 153
- Python 的 __name__ 变量,到底是个什么东西?
- 值得一看的文本检测方法