NOIP算法概论

之前高一参加比赛前,曾写过总结,主要是提醒自己NOIP所需要的基本算法,以及至少所需要掌握的数据结构。

当然,NOIP,最重要的算法,只有一个,THAT IS “搜索大法”

练好了搜索,今后的所有竞赛,题目哪怕拿不了满分,至少30+,说不定60+。自己脑补一下优化,100分就到手啦。。。

第一篇正儿八经的博客(别管前面那篇):请各位OIER们,一定一定,要练习搜索,必须练习搜索,而且搜索MUST成为你最拿手的算法!!!

今天的主题是算法概论,就是大概提及一下各个算法啦,貌似也有些没提及(那就拜托无所不能的度娘啦,不过有些具体的算法,我会在后面具体提到的)。

AND 这是高一写的稿子,有啥表述不清的,甚至错误的,请各位体谅!

一.基础思想

1.1二分答案

   noip考试中经常会出现二分答案题目,二分答案,其实是一种思想而并非一种准确的算法,多与模拟,贪心,图论算法相结合。比如说noip2015day2第一题跳石头,noip疫情控制,noip借教室等好多题都可以考虑这种思想。尤其是题目中出现了最大值最小或是最小值最大一般都是二分答案。所以,考试时必须时刻提醒自己要注意往二分答案这方面想。那么二分答案为什么难呢,其一是压根就没往这方面想,其二就是很难check()。check()才是二分答案的关键,容易的直接贪心模拟,比如去年的跳石头,但疫情控制则是二分答案+倍增+贪心的组合题。

那么对于如何书写好check,那就只能靠个人能力了。不过,我们思考时一定要抓住当前分出的答案mid,想好如何会使所求解不满足于当前答案,当发现所求解>mid时该怎么办。从这几个方向去思考会比较容易的得出答案。

1.2贪心

   贪心可以是最不靠谱的解法,也可以是最靠谱的解法。一切都要看你如何去贪,再你码完搜索不会写时,贪心可以帮你。不过除非你百分之百确定贪心的正确性,最好不要只交个贪心上去。贪心其实与最难的dp有很多相像之处,但最大的区别就是有无后效性。这类题目在noip中出现也很多,容易题有不少,但是很多难题多多少少有些思想在其中。这一部分只能考试前多刷题,提高思考能力,考试时自己好好想。    

1.3分治

   分治也是思想,有太多的数据结构,算法要用到分治了。二分答案虽然被我拿出去那是因为太重要了,但二分答案说到根本还是分治思想。分治可以对于多个对象分,答案可以分,操作可以分,最常见的还是算法分治。也就是用分治算法解题,比如:解方程,求平面各种点对等等题目。

1.4倍增

   倍增也是几乎年年多考的题目,倍增,就是字面上的意思,成倍的增长,成倍的跳跃。可以在树上倍增比如说求解lca,在图上同样也可以倍增。倍增多适用于询问很多,但很少修改的题目。如果修改多的话,多用线段树,树链剖分维护。倍增需要注意的地方就是先前的预处理上,以lca举例,预处理时我们求解x的祖先时就要注意(1<<i)<dep[x]。求lca时,先求出两者的差,从小到大枚举,保证(1<<i)&t,使得两者处于同一高度,然后从大到小枚举,保证每次两者的祖先不相等的情况下跳跃。考试时打完倍增一定要注意认真检查,倍增中有很多细节,万一你从大到小搞反了,马上就是0分。

1.5动归

   动态规划,一直以来OIER考试中最难的题目类型。动归也是我最差的算法,难就难在难设计状态,难在如何根据状态找出关系,推出方程。当然,对于这类题目也不是全无办法,最好的就是搜索,把搜索的状态设计好后就可以打出记忆化搜索,记忆化虽然逊色于动归,但如果状态设计的好切题也不是问题。动归在考前就一定要从简单模板开始打起,先把各钟模板打好,然后在认真思考想方法将模板复杂度减小(其实很有用,很多考试都会考模板,但关键是你能否看出来,看出来后能否保证不会超时)。动归考的是个人的分析题目能力,这只能靠多写题,多思考,多请教别人来提高。

二.图论

2.1 SPFA

SPFA是Bellman-ford算法的优化,其实就是在此基础上加了个队列优化,使得只有每次被更新的才会进入队列。SPFA算法时间复杂度更Dijkstra+堆差不多,但是相比而言,Dijkstra+堆更加稳定。

2.2 Dijkstra+heap   

    迪杰斯特拉加堆与SPFA一样,都是求单源最短路径,也就是一个起点,一个终点。但要比SPFA稳定的多,并不容易被随意卡掉。NOIP中此算法用的很多。代码详见资料。

2.3树链剖分

    树链剖分针对的是树上的操作,通常题目要么对于树上是有修改操作的,要么则是求树中一条路径上的最大值/最小值/其它与边息息相关的。

2.4 LCA

    树上最近公共祖先,这个考点一直以来考得很多。之前考得货车运输就是一道裸的lca题目,还有好几题都需要运用到lca。求lca大概有三种方法。第一种就是倍增,倍增在求lca中用的极多,也很好写,只要不把for的顺序搞反一般就没事了。树链剖分也可以求解lca,这一般是比较难的题才用的,因为树链剖分支持树上权值修改,虽然不好打,但可以快速修改,快速询问。第三种是树状数组求lca,用的比较少,就不说了。

2.5拓扑排序

    拓扑排序是在有向无环图上进行的操作,作用是求出一个先后顺序。当然,拓扑排序也可以起到判断有无环,若有环,那么一定进行。在noip考试中拓扑排序考得并不多,但是当我们看到要求操作的先后顺序时,拓扑排序就大有作用了。算法很简单,每次选入度为0的点加入拓扑序列,将与此点直接连通的所有点的入度全部减一,由此重复下去直到不满足为止。

2.6生成树

    生成树在noip考试中用的很多,最小生成树,最大生成树更是经常用到。虽然考试不见得会考裸题目,但是很多题目都得先用生成树将图转变为树后,再在树上进行操作。求最小大生成树都是用克鲁斯卡尔,即贪心思想+并查集。这类题目很灵活,但关键是分析具体题目并求解。

2.7 tarjan

    tarjan算法才是图论中的重难点。tarjan算法用处很多,诸如:求强连通分量,强连通图,割点,割边(桥),还可以将求出的强连通分量缩点。

算法主要部分就是dfs,其中起关键作用的就是low[]数组和dfn[]数组。两个数组都是记录dfs访问到的时间的,low数组是指最早访问到的时间,dfn数组则是指最近一次访问到的时间。

求强连通分量,每一次递归时low[u]=dfn[u]=index++;index是访问时间,而在通过u节点扩展时,若发现(u,v)相连,且v节点未被访问过,那么low[u]=min(low[u],low[v]);(意思就是说因为v是u的子节点,若发现之前曾访问过v节点,则此时更新low[u]的值)。若发现v已经访问过了,那么low[u]=min(low[u],dfn[v]),意思就是说让子树根的low编号最小。当发现low[u]==dfn[u]时就可以判定此点为强连通子图的根,那么此时就可以直接让控制stack的sp指针-,将元素出栈输出了。若要求连通图,想必也是这里动手脚

求割点:若low[v]>=dfn[u],则u为割点,节点v的子孙和节点u形成一个块。因为这说明v的子孙不能够通过其他边到达u的祖先,这样去掉u之后,图必然分裂为两个子图。这样我们处理点u时,首先递归u的子节点v,然后从v回溯至u后,如果发现上述不等式成立,则找到了一个割点u,并且u和v的子树构成一个块。

求桥:若low[v]>dfn[u],则(u,v)为割边。但是实际处理时我们并不这样判断,因为有的图上可能有重边,这样不好处理。我们记录每条边的标号(一条无向边拆成的两条有向边标号相同),记录每个点的父亲到它的边的标号,如果边(u,v)是v的父亲边,就不能用dfn[u]更新low[v]。这样如果遍历完v的所有子节点后,发现low[v]=dfn[v],说明u的父亲边(u,v)为割边。

2.8缩点

    缩点在noip考试中经常会用到,缩点一般是用并查集将所有连通块求出。通过fa数组即可知这n个点将会被缩成几个点,可以用于优化。除此,由于tarjan算法可以求出强连通分量,所以tarjan也可以进行缩点。

2.9强连通分量

    前面tarjan算法中曾介绍过此算法,在此不做介绍。

2.10 二分图

    二分图匹配也是图论的重要算法,求最大匹配可以用匈牙利算法,求最大完美匹配则是用KM算法,虽然它们的理论复杂度并不低,但实际上却是跑的很快。二分图与网络流密不可分,由于难度问题,在联赛中考的不多。

2.11 网络流

    网络流分为费用流和最大流。两类题目几乎不考,当然,如果没有其他方法,也可以往网络流这方面想。

2.12 并查集

    最基础的图论算法之一,前面写了蛮多用到并查集的算法(生成树,缩点),有很多题目都可以用并查集来维护。思想很简单,每个点最初都是一个独立的连通块,若有边与之相连,那么就将它们fa值赋为一样,即在同一连通块中。

三.字符串处理

3.1 kmp

    KMP算法是最基础的字符串算法,用于字符串快速匹配。算法很简单,核心思想就是失败数组的运用,但利用kmp算法的过程出一些比较鬼的题目。比如说:codevs上的动物园,

3.2哈希

    哈希算法很好写,hash[i]=hash[i-1]*p+s[i],p一般取31,而mod一般为1e9+7。对于字符串的子串的哈希值等于hash[r]-hash[l-1]*(p^(r-l+1))。

四.搜索

4.1 DFS

    DFS作为最基本的暴力算法,每一场考试都会考。要注意设计DFS的状态,还要注意不会走回头路。但是,在迷宫等求解方案的时候还是多用BFS。

4.2 BFS

   BFS一般相对DFS用的少一些,多用于迷宫路径求解。

4.3 记忆化搜索

     记忆化搜索并不是每道题都可以的,有些题可以,也有些题不行。一般如果满足无论何时到达此点,此点和到达此点之后的状态都不变的情况下就可以用记忆化搜索。如果重复到达此点后状态发生了改变那么记忆化搜索就不适用了。记忆化搜索是解决可以dp的问题的好方法之一。当然,设计的状态也一定要设计好。

 

 

五.其它

5.1 快速幂

快速幂就不多说了吧,算法的核心是将x^y用二进制来乘,与矩阵快速幂一样。

Res=x;while(y>0) if(y&1) res=res*x%mod;x=(x*x)%mod,y>>=1;这样就可以使速度达到log级别。

5.2 高精度

    高精度是个很麻烦的东西呀,现打很容易出现错误。但是,有些题目,满分only高精度。这一方面,自己一定要多练习,搞清原理后,有事没事打一打。嘿嘿?

5.3 逆序对

    求解逆序对有两种方法,要么归并排序,要么用树状数组求解。考试中考的还是挺多的,一般都是序列问题。后面会具体介绍。

5.4 离散化

     是否离散化,跟题目类型,题目数据有很大关系,请各位出门左转,度娘搜一波,满满的方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值