前言
本周在课上进一步学习了二分法,以及通过老师的讲解,了解了更多有关二分的例题,同时也对递归算法、搜索(深搜和广搜)学习了一部分,以下是对本周所学二分的复习总结,以及对递归和搜索的介绍,以及课堂上以及平时的总结
一、二分法
对最值问题的求解
1、求最大值的最小,即求解二分最大值,判断条件满足后,尽量让答案往前来,对应模板1(上篇文章)
2、求最小值的最大,即求解二分最小值,判断条件满足后,尽量让答案往后走,对应模板2
二、递归
1.概念(分为递和归):
在函数的定义中使用函数自身的方法
2.思想:分解为递和归两个过程
递:递归问题必须可以分解为若干个规模较小,与原问题形式相同的子问题,这些子问题可以用相同的解题思路来解决(即可分解相同(似)子问题)
归:大问题分为小问题后,到达临界值,再从这个临界点开始,原路返回到原点,原问题解决
3.关键:
(1)递归定义(即递归数学表达式,或者规律)
(2)递归终止的临界条件
4.伪码:
~ f()
{
if //判断出口(边界判断)
return ~
else return ~
}
三、搜索(DFS、BFS)
1.概念:对所有结果按照一定方式进行遍历,直至找到所求结果(答案)的过程
2.分类:深度优先搜索、广度优先搜索
3.深度优先搜索
(1)概念:属于一种遍历所有结果的算法,即从起点出发,走过的点要做标记,发现有没走过的点,就随意挑一个往前走,走不了就回退
(2)特点:
思想特点:暴力枚举,朝一个方向走到底,再回退,如果中途就不满足就应该立即返回(即剪枝),但深搜属于盲目搜索,时间复杂度最大可达到O(!n)
解决问题特点:对于解决遍历和求所有问题有效,对于问题搜索深度小的时候处理速度迅速,然而在深度很大的情况下效率不高
(3)伪码:
int depth;
bool Dfs(V)
{
if( V为终点)
{
path[depth] = V;
return true;
}
if( V 为旧点)
return false; //将V标记为旧点;
path[depth]=V;
++depth;
//对和V相邻的每个节点U
if( Dfs(U) == true)
return true;
--depth; //回到上一步
return false;
}
int main()
{
//将所有点都标记为新点;
depth = 0;
if( Dfs(起点))
{
for(int i = 0;i <= depth; ++ i)
cout << path[i] << endl;
}
}
4.广度优先搜索
(1)概念:对顶点一个个检查,对同级的顶点检查完之后入列,再检查下一级的顶点,依次进行到最后,直至结果出现
(2)思想特点:
按照“平推”的方式向前搜索,而且对于解决最短或最少问题特别有效,而且寻找深度小,但缺点是内存耗费量大(需要开大量的数组单元用来存储状态)
总结
通过课上对递归以及搜索的学习,对细节上的问题作出下面的一些总结:
递归:
(1)当出现相同调用时,最优化的方式是先算出相同调用的算式,再将相同调用算式进行运算(因为每一次的调用都是一次递归,调用次数增多会导致时间复杂度提高)
例如:l=f(),return l*l;
(2)在ACM写代码过程中,最好定义全局变量,而不是局部变量,不用传递参数,而且储存的容量大,能很好的解决递归不易传参的问题。递归给参一般有两种形式,一个是全局变量,另一个就是传递形参(较麻烦)
搜索:
DFS、BFS区别
(1)遍历区别:
深度优先搜索DFS:一个递归过程,有回退过程。尽可能“深”地搜索。在深度优先搜索中,对于最新发现的顶点,如果它还有以此为起点但没找到的边,就沿此边继续搜索下去。当结点V的所有边都已被搜索过,搜索将回溯到发现结点V有那条边的始结点,则选择其中一个作为源结点并重复以上过程,整个进程反复进行直到所有结点都被发现为止。
广度优先搜索BFS:一个分层的搜索过程,没有回退过程,是非递归的。只是每次都尽可能地扩展当前节点的邻居节点,之后再向其子结点进行扩展。
(2)解决问题区别:
BFS 常用于找单一的最短路线,它的特点是 “搜到就是最优解”(实际问题解决中可能要用到优先队列),而 DFS 用于找所有解的问题,它的空间效率高,而且找到的不一定是最优解,必须记录并完成整个搜索,故一般情况下,深搜需要非常高效的剪枝