1、碎碎念
我的算法启蒙来自于紫书算法竞赛入门经典,但是不得不说从语言过度到算法,紫书并不是一个很好的开始。当时整本书除了数学和图论其实是看完了的,但真的有印象的大约只有暴力枚举法中枚举排列,子集生成和八皇后这3个经典例题。数据结构章节的树图链表UVA例题都做了,但是早已没有任何印象。高效算法设计那章隐约记得快速排序,其他没了。动态规划就记得数字三角形,DAG那章当时没学会。可以说,紫书的晦涩难懂直接卡了我好久,整本书学了啥就会枚举三例题。。。紫书更多的是给了我一个从C++过度到算法的过程。真正意义上的启蒙来自于挑战程序设计竞赛这本书,全书POJ例题和ACM训练,初级篇对初学者真的很亲切友好,也是在这里我学会了基础的穷竭搜索(DFS,BFS,剪枝),学会了贪心的几个例子(印象最深的是哈夫曼编码),学会了简单的动态规划(尤其是数字三角形,背包九讲),学会了一些数据结构包括树,优先队列,并查集。学会了图的最短路和最小生成树,学了辗转相除法,素数判定,快速幂等等。虽然很遗憾中级篇和高级篇没能坚持看完。期间另一本书啊哈算法对我高级数据结构包括图论知识(最短路,生成树,割点割边,二分图,并查集)的深入理解和巩固起到了很大的作用。之后在线下培训和洛谷网课中,可以说从广度上涵盖到了算法竞赛。先后学习了NOIP三大数据结构中的线段树,树状数组,优先队列。零零碎碎的树剖和ST表,RMQ,差分,分块等等也在线下课学过。洛谷上学了图的强连通tarjan,最近公共LCA,二分图匹配。学习了数学的gcd和exgcd,同余方程,剩余定理,计数原理之类的(不过现在似乎都忘记了),也学了拓扑排序和动态规划,区间DP,树形DP,状压DP等等。期间信息学奥赛一本通对我帮助也很大,尤其是DP那一块。也会会NOIP相关的codevs和vijos等OJ。再之后深入是用的算法竞赛进阶指南,平衡树,网络流,都是在那里学的。还有一本信息学高赛提高篇,学习了字符串相关内容。那阶段主要是水BZOJ,LOJ和UOJ。
2、算法启蒙
纵观我的学习经历,可以说像是走马观花,没有目标的在整个圈子里兜兜转转。广度有了,几乎任何一个叫得出名字的算法我都有点印象,但是至少有50%我现在写不出来,30%当时就没学会。我觉得自己少了很多核心的东西。什么是算法,什么是数据结构,它们之间有什么关系?算法是用来解决问题的,换句话说,没有问题,那算法是没有意义的。设计算法的时候,是结合实际问题不同的特征来设计的。数据结构是维护一组特定的数据的,他们有某种共同的特征。 换句话说,可以设计与之相应的某些特定的算法。比如树的遍历存储DP维护,图的最短路生成树割点割边连通性网络流,比如序列的分块差分前缀和线段树,等等等。在某种数据结构上能用的算法,到另外的数据结构上很可能就不能用了。算法是用来解决问题的,一个实际问题的各种可能情况构成的集合称为状态空间。而程序的运行,就是对状态空间的遍历。数据结构通过划分,提取,抽象来组织特定的数据形式。算法则是在此基础上用以解决该问题。暴力和枚举理论上可以解决所有问题(只要你能表述出状态空间),而算法则是去优化速度与效率。特定的遍历方式对应特定的状态空间。 如多项式级的一边用for递推遍历,指数级的一般用递归或位运算遍历,排列级的用next_permutation遍历,组合级的用递归加剪枝遍历。数据结构与算法,是一个整体系统的结构与功能的关系。结构有某些特点,用以实现某个具体的功能(解决某个问题)。数据结构分类:从序列,到一叉树(链表),到二叉树,到多叉树,到图。。分为一对一,一对多,多对多这3类。经典算法的使用场景:kurscal,dijkstar,folyd,prim,等等,要了解算法的功能(不然算法本身是没有意义的。。),平衡树,线段树维护的数据。了解经典算法的时空复杂度,能够分析问题的数据规模和复杂度,如1s钟差不多能处理1e7的数据。为什么学了很多算法和数据结构,遇到新问题的时候还是没有想法?因为问题的突破口永远来自于问题本身,题目中的条件去掉和存在会使整个问题完全不一样。设计算法的时候,可以用苯办法优化。比如从搜索到动态规划,,搜索本身有一个状态,搜索往下走的时候就是一个状态转移,而动态规划的本质就是状态和状态转移方程式。想到搜索后变成记忆化搜索就是动态规划。一步想到正确解法除非你做过这个题,这是不可能的。算法和数据结构的联系只在于这个问题是否恰好需要这些操作,如果需要,那就搬过来。 数据结构是加速算法的一种手段,有了那些基础操作以后,算法能够解决更多的问题。