蓝桥杯算法之搜索章 - 2

大家好,接下来,我将带来对于搜索篇的新内容,这部分我将打算围绕DFS深度优先搜索去讲解。

温馨提示:由于这篇文章是接着上一篇文章的,如果新读者没有看过前一篇的话,推荐去看一下,不然有些地方可能会不懂。

接下来的每道题我相信大家都会有所收获的!

1.题目概述:

这部分我将讲解以下有关DFS的题目

1.选数 --- P1036 [NOIP 2002 普及组] 选数 - 洛谷

2.飞机降落 --- P9241 [蓝桥杯 2023 省 B] 飞机降落 - 洛谷

3.八皇后 --- P1219 [USACO1.5] 八皇后 Checker Challenge - 洛谷

4.数独 --- P1784 数独 - 洛谷

这部分的题比上篇文章的题难度要提高挺多,大家可以如果有所困难可以多多思考一下。

2.选数

大家会发现,如果看了我前面的算法篇1的话其实很容易解决dfs递归的内容的。

但是大家会发现这里有一个新问题:如何求解一个数是不是素数呢?

这个的话有挺多的方法的,我在这里就用了一个简单的方法

比如判断一个数x是不是素数,由素数的定义我们可以知道:素数是大于1的正整数,而且只能被自己和1整除。

那么我们就可以从2开始到x所有的数 拿去试除即可解决。

但是要判断的这些数有点多了,我们就可以去选择试除到根号x即可,具体的原因网上有证明,有兴趣的读者可以去看看。

(如果想判断大量数字是否为素数,可以采用埃拉托色尼筛选法

大家在看题目,发现结果并不会因为数字的顺序不同而改变,所以是一种组合。

我们就得在dfs的参数中加入一个begin参数来表示从哪个数开始的

首先我们画一下这个决策树:

我们根据自己画的决策树就可以来写代码了:

当然这道题跟上篇文章中的思路是一样的,回溯递归

3.飞机降落

这道题的难度就比较高了,大家好好理解一下题目,可以尝试做一做

那跟着博主的思路一起来看一下这道题吧。

这道题会发现的是如果直接来做的话,要安排好每架飞机的顺序,保证该组飞机能够安全降落,那么如果怎么都安排不出来,就代表这个不能及时降落了。所以如何安排顺序就是我们的问题了

我们这时候就可以通过搜索去枚举出来所有情况。而且数据也是比较小的,通过搜索去做也不会出现超时,很显然也在暗示我们去搜索。

由于这道题的枚举类似排列 ,所以我们就不需要一个begin值去告诉该从什么位置递归了。

对于安排过的飞机,我们只需要通过一个bool st[]数组去标记一下即可。

当遇到了标记过的飞机就直接剪掉这个分支。

上一架飞机结束时间需要记录一下,因为上一架飞机结束时间 > 新飞机到达时间 + 最长盘旋时间,就代表了新飞机无法降落,我们也将这个分支给剪掉。

那对于新飞机的结束时间怎么计算呢?

1.新飞机到达时间 >= 前一架飞机结束时间(新飞机到达的时间晚于前一架飞机的结束)

那么新飞机结束时间 = 新飞机的到达时间 + 新飞机的降落时间

2.新飞机到达时间 < 前一架飞机结束时间

比较一下

新飞机到达时间 + 盘旋时间 是否大于等于 前一架飞机结束时间

如果是----> 新飞机能正常降落 ---- 新飞机结束时间 = 前一架飞机结束时间 + 新飞机降落时间

如果不是 ---> 新飞机无法正常降落

所以新飞机的结束时间 = max(前飞机的结束时间, 新飞机到达时间) + 新飞机降落时间

根据博主的思路大家好好想想,将这个条件理解后,我们就可以来实现代码了。

读者可以先尝试写一下

这样就可以实现出这到题了

大家可以仔细理解一下。

4.八皇后

大家还是可以先自己做一下,看看有哪里不懂的。

接下来就跟着博主的思路来理一下这道题吧,我们看完这道题后,我们知道的是什么呢?

我们无非就是要往这个矩阵中填棋子,将解的个数输出即可。

我们对应的布局就如下面这样

对应的246135数字都为对应的1,2,3,4,5,6行对应的列

所以我们有了对应的数字246135就可以得到对应的棋局布置了

我们可以发现数据并不是很大,我们就可以去尝试枚举所有的情况了,将所有棋子的填充情况都枚举一遍不就解决了吗?

我们要填数肯定也有对应的限制了,那么限制是什么呢?

题目有说:行、列、对角线至多只能有一个棋子

所以我们通过这个条件就能够减少我们枚举的个数

我们简单画一下决策树来:

这里并没有画完,大概理解一下,我们只要遍历填充即可

大概逻辑还是dfs将结果存放起来

我们发现,其实要知道对应的行列有没有放棋子很简单的,由于放了1行,那么只能从2行开始放置了。所以我们只要用循环一行一行的放 即可,我们再创建一个bool col[N]数组去标记哪些列被标记了。如果对应的列被放了就跳过它。

那么对角线如何解决呢?

我们可以使用一次函数来解决它。以向下的行数为x轴,向右的列为y轴,每个对角线都有自己的一个表达式:

我们对于一个坐标位置就有两条对角线:y - x = n y + x = n

如果满足y - x = n或者y + x = n就代表对应的对角线已经有了棋子了!

我们只要将填过棋子的y - x 和 y + x得到的值 放在对应的数组就可以标记对角线了

但是有可能y - x会出现负数?怎么解决呢?

我们只要给**y - x加上一个n值(偏移量)**即可

现在bool st[2 * N] ;就可以标记对角线 了,而且由于每个节点会出现两条对角线 ,所以要空间要开辟2 * N的大小!

我们需要统计前几个结果的路径所以还得用vector<int> path去标记成功的结果。

现在我们就来写一下代码吧:

大家可以好好理解一下这段代码,再和博主我的思路画图结合一起来分析。

大家理解了其中的主要思维,就能够自己写出来了

5.数独

这道题题目讲的很简单给出一个未知的数独,然后让我们把它填完,再输出即可。

大家还是一样可以先自己思考一下该如何解决!

下面跟着博主的思路来看看这道题吧:

首先我们会接收到一个二维数组,这里面会有很多0,这些0就是我们需要去填充的部分

对于每个0我们都可以在1---9的数字去填充

但是会因为其他已经有了数字的位置导致有些数不能填。

玩过数独的都知道,我们每行都是要在1-9去填充,3 * 3的格子内也得要在1--9

对于对应的行列,我们可以使用一个二维数组去标记第几行的哪几个数被填过,第几列的哪些数被填过。

bool row[N][N] ---------- row[i][x]表示第x行的i数被填充过

bool col[N][N] ---------- col[i][y]表示第y列的i数被填充过

那么对于这个3 * 3的格子怎么解决呢?

我们看看下面的图:

我们只要下标从 0 --- 8来标记数组,就可以通过对应的下标除以3就可以得到是第几个3 * 3的小格子

对应的这9 * 9的数独就有9个3 * 3的格子,就可以用对应点的x, y通过x / 3 , y / 3去找到对应的3 * 3格子

我们创建一个三维数组st来标记即可解决了

bool st[N][N][N] ----- st[x / 3][y / 3][i] ---- 就代表第x / 3,行y / 3列的3 * 3格子中填充了数i

现在我们最困难的地方已经解决,现在就是写代码的阶段,读者可以跟着思路自己去写一下!

代码如下:

这道题中dfs里面还多出来了个判断y和x的合法性的判断,这个地方需要特别注意一下。

6.结语

很高兴大家能够看到这里,这一部分的题难度有所提高,大家要好好思考思考。

好好理解其中的思考过程,相信大家会有所收获的。

后面我会持续更新,大家多多点赞收藏+关注。

相关推荐
郝学胜-神的一滴1 分钟前
OpenGL状态机与对象管理:优化图形渲染的高效方法
开发语言·c++·程序人生·算法·图形渲染
MSXmiao33 分钟前
2048小游戏
数据结构·c++·算法
CoovallyAIHub1 小时前
论文精读|YOLO系列最新模型水下实测:v8为何能斩获80.9% mAP?
深度学习·算法·计算机视觉
Ghost-Face1 小时前
《算法导论》笔记--归并排序 & 算法原理
算法
好好研究2 小时前
Java基础学习(一):类名规范、返回值、注释、数据类型
java·学习·算法
C++、Java和Python的菜鸟2 小时前
第二章 矩阵
人工智能·算法·矩阵
阑梦清川2 小时前
搜索算法---填涂颜色问题(在外围添加多余的0的求解方法)
算法
2301_763994712 小时前
c++11特性
数据结构·c++·算法
快去睡觉~3 小时前
力扣148:排序链表
算法·leetcode·链表