Jerry @DOA&INPAC, SJTU

Working out everything from the first principles.

导航

算法基础课程总结

程序设计与算法(二)算法基础,讲授基本的算法。前置课程为程序设计入门,后续是C++ OOP,夹在中间的这门课难度不高,使用的工具也比较基础,这让PAT甲级满分的我在听课时甚至有些尴尬。不过好在课程中使用的都是C++语言,相较于之前学的数据结构课程,这一点让我无比舒适。

“本课程中一部分的例题,难度与中学信息学奥赛NOIP提高组的较难题相当,也和ACM国际大学生程序设计竞赛中的中等题相当。”ACM什么的我不关心,但是即将参加CCF-S的我怀疑例题是否达到NOIP的难度,因为听课过程中几乎没有难以理解的地方,甚至很多都是快进跳过的,而练习题也比较轻松解决了。然而NOIP题我看一眼就不会做。

为了考试,我得继续学算法,目前定为算法设计与分析之入门篇算法设计与分析之进阶篇和《算法导论》。在开始新的课程之前,我先把刚学完的课程总结一下。

 

枚举

以前一直觉得枚举就是把所有可能值穷举一遍,是非常耗时的。然而很多情况下只需要对几个变量进行枚举,其他的可以由此推导出来,这样枚举量就可以指数下降了。事实上很少有题目会允许全部枚举而不超时。

递归

递归本身没什么好讲的,从最初学编程就开始接触了。

Boolean Expression这道题为我将来写汇编器提供了一点启发。

简单的整数划分问题,输入为[1,50]的整数,输出也是一个整数,让我想到这个问题完全可以编译期完成,而C++模板本来就是擅长递归的。有机会专门写一篇模板元编程,这道题就是一个很好的应用。

二分算法

二分算法已经在搜索等应用中写了很久了,但它在题目中的用法对我来说是新知识。如果一个输出量与输入量是单调的关系,就可以考虑使用二分算法确定输出量受约束时输入量的极值。

分治

完全不记得分治讲了什么,赶紧回去翻了翻讲义。例题和练习都是“输出前k大的数”和“求排列的逆序数”。我感觉这两个算法都是比较难想的,只有输入数据规模提示了才能明确优化的目标,即O(n)或O(nlogn)。

一个很常用的结论是,如果分治合并的过程的时间复杂度是O(n),那么总体时间复杂度是O(nlogn)。反过来讲,如果能猜出一道题要求写O(nlogn)的算法,并且可以用分治解决,合并的过程不能超过O(n)。

动态规划

之前在PAT做题的时候,还没学DP,就开始做DP的题了。看别人的博文学了01背包,也利用动规的方法做对过题目。这回是系统的学习了。

课程中讲的递归化动规的方法我不是很明白,状态转移方程比较好理解,只是具体问题中如何确定变量和转移方程,需要沉下心来思考。有时候内存会超限,可以考虑滚动数组。

现在还不怎么熟练,一小时一题的速度肯定是不够的,还得多做题。以及国庆期间做到这里的时候POJ崩了,出现了从没见过的validator error。

深度优先搜索

学数据结构的时候,DFS好像没有什么存在感,拓扑排序、Dijkstra等都是类似BFS的算法,只记得有一些题目DFS和并查集都能解决。

而实际上DFS的能力还挺强的,据说几乎所有的图问题都可以用DFS解决。但是,DFS中需要保存路径,并且不保证第一个解是最优解。为了提高效率,可以加入可行性剪枝与最优性剪枝。

广度优先搜索

一些问题中变量代表着状态,状态之间的转移与变量之间的关系有关,这样的问题就可以等效为图,其中状态为顶点,关系为边,可以用图的方法来解决。

贪心算法

第一次见识到算法的证明如此繁琐。对于一些题目,贪心的取法比较复杂,不容易想到,尤其是最后一题田忌赛马,POJ还不给测试数据。后来去查了答案才会做。

 

用一句话来总结这门课:原来以前学过的东西还可以这么用

 

posted on 2019-10-10 22:00  Jerry_SJTU  阅读(903)  评论(0编辑  收藏  举报