蓝桥杯算法之搜索章 - 3
大家好,通过前面两章的讲解,我们已经了解了搜索中的DFS深度优先搜索。
接下来我们将接着讲解剪枝与优化,更加深入的理解我们的DFS搜索
学会如何去优化我们的搜索,减少递归的次数
1.剪枝与优化
开始大家可能想知道剪枝是什么呢?
其实从名字上来看就是剪掉枝丫,枝丫这东西肯定是树上面有的啊
所以我们很容易想到,剪枝与优化其实就是剪掉搜索树多余的分支
从而减小搜索树的规模了
通过剪枝与优化我们就可以优化时间复杂度!
在我们的深度优先搜索DFS中,有以下的常见剪枝方法:
1.排除等效冗余
如果在搜索过程中,从某一个节点往下的存在许多最终结果等效的分支,那我们就可以只去搜索其中一条分支。
2.可行性剪枝
如果在搜索过程中,发现有一条分支怎么都不能拿到结果我们就将它剪掉,搜索其他的分支,减少搜索
3.最优性剪枝
在最优化的问题之中,如果出现分支已经超过了最优解的值,就不去继续进行搜索了。因为这条分支肯定不是最优解了,该分支往后的肯定也不会是最优解了。我们此时就该去搜索其他情况了
4.优化搜索顺序
在有些搜索的问题中,搜索的顺序是不影响搜索结果的,此时搜索顺序不同就会导致搜索树的规模差距很大。因此,应当先选择一个搜索规模小的顺序选出最优的答案,再通过最优性剪枝剪掉其余部分
5.记忆化搜索
记录每一个状态的搜索结果,当下次搜索到该状态的时候我们直接拿结果就是。这样就避免了多余的搜索。
记忆化搜索,有时也叫动态规划
2.题目part1
2.1.数的划分
P1025 [NOIP 2001 提高组] 数的划分 - 洛谷
这道题题目还是比较简单,我们简单画一个决策树看看:
我们从题目可以知道顺序相同代表了同一种答案,所以是一种类似组合的dfs
我们只要满足结果和为7即可让分法+1
那我们其实就很容易写出最简单版本的递归了:
dfs(int pos, int begin);pos记录当前层数,begin记录从第几个数开始
我们先来看一下没有涉及剪枝版本的代码是如何的吧:
我们提交后,明显发现有例子没有通过。TLE就是代表超时了,我们显然不剪枝就很难通过它,我们就来看看有哪里可以剪枝的吧:
我们从画的决策图中可以发现当每次一条分支的最小值如果都大于了n那么我们就可以不去递归这条分支了,直接剪掉。分支的最小值:begin * (k - pos + 1) + path
代表节点之前的和 path + 节点往下(包括这个节点)的层数 (k - pos + 1) * 最小值begin
即我们算的是分支最左边的那条的和就是最小值
这个就是所谓的可行性剪枝了。
我们就在看一下对应代码:
但是这里还是有一个例子过不了?为什么?
其实是因为这道题要求比较高,我们还需要优化一下:
我们观察一下代码会发现,我们剪枝的位置是必须要进入节点才去判断,并且将它剪掉。
可是如果我们进入节点再去剪枝就会产生生成对应节点的时间浪费了
我们如果使得还没有进入节点就去剪枝呢?这样就可以更加优化这个代码了,当然如果看过我之前的两篇文章的话应该都知道。我会将判断拿进for循环里面去判断。
看一下优化后的代码吧:
大家这里可以好好理解一下!
因为我们的path此时还没有加上当前的begin,所以path不用动,而且k - pos + 1也是代表了当前节点到最下面节点还有几个节点的个数。唯一变化的是begin变成了i。这个也是可以理解的,因为i就是去遍历对应的begin来着。
2.2.小猫爬山
P10483 小猫爬山 - 洛谷
我们看完题目,可以知道的是我们要安排小猫,我们只要dfs深度优先搜索,找出结果即可。
安排小猫我们肯定是先安排到同一辆车中,判断一下超过对应的车辆重量超没有,超了就重新开一辆
我们需要最小的车数,我们只要加入一个创建两个变量,一个存当前车辆数和最小车辆数。判断一下就可以得到最小值了
那么我们就可以写出一个最简单的版本:
这个位置我对于ret赋值为0x3f3f3f3f,去初始化一下,将它初始化成一个最大值
我们看代码最后有很多结果都超时了,这就代表我们还需要进行剪枝才能解决这个问题
那我们有哪些位置可以剪枝呢?
我们最简单的就是最优性剪枝:我们将安排完18个小猫后再去判断cnt和ret的方法改一下:
改成先判断cnt是否大于ret,如果出现大于我们就直接剪枝
将这个部分改了之后,居然直接就过了?
我们剪枝的效果很明显!
其实我们这里还有更进一步的剪枝:优化搜索顺序
我们如果随机安排小猫的话也是可以过的。但是如果我们将小猫从大到小来安排
那么我们的车很容易就被塞满,就可以很快地减少大量的分支了。
那么我们的最终代码为:
我们观察一下对应的运行时间也可以发现,修改后的最终版本明显是要快一些的。
3.结语
以上便是我们剪枝与优化的一部分内容了,我们还有一个记忆化搜索的内容在之后的文章。博主将尽快更新,大家可以多多关注和点赞收藏。方便即时看到后续内容,如果以上部分有什么地方有问题的可以私信博主或者在评论一下。
希望大家能够有所收获!