ACM课程学习总结

ACM课程已经到了结尾了,通过这一学期的学习虽然不能说老师讲的东西完完全全掌握了,但是还是学到很多东西,不单单指学习的内容,还包括一些学习的方法。

我选择ACM这个课程的原因是这样的:其实上个学期我的选修课已经选完了(除了ACM),当时咨询了老师什么是ACM,还在犹豫考虑报不报,其实这个课程的分类是分流课,不在我们必须修满的课程类别里面,只是想是不是能多提高一下自己。回忆起高中高一的时候,有报信息学竞赛的,但我顾及其他课程,会分不出来精力来做这个,现在大学时间相对来说宽松一些,想看看自己是不是有这方面的能力,即使没有也可以学点其他人没有学到的东西,也是很好的。于是和班里其他人一起报了这个课。

其实ACM课程的学习并不是从这个学期开始的而是大一的寒假就开始了,放假前,老师让我们自学STL,在群里发了一下资料,并出了一套题让我们练手,放假前我打印好STL的书,寒假学习STL。因为以前从来没怎么接触过这个东西,必须从0开始学。不过书写的内容很详细,读起来不是太难,但为了加深印象,我还是实际一边看书一边把书上的代码实际打了一边并运行,书中好像有些标准不适合,代码有的不能运行,自己根据实际情况改了一下,学习STL的时候遇到的几个难题,一个就是自定义比较比较函数,因为大一上学期没学过重载运算符,看起来云里雾里,不过每个容器都有这个东西,看多了大概就是知道是怎么写的了,最后用起来也是根据已有经验套的。还有就是有些容器学起来很费劲,例如bitset容器,list双向链表容器,deque双端队列容器等,不过用的不太多。最后还有,因为没学过数据结构,书里一些名词不是很懂,例如红黑树,二叉树,链表之类的。不过庆幸的是这些并不会对运用STL产生很大的障碍,只不过不理解底层是怎么操作的罢了。书后半部分的例题都是运用前面所讲的STL做的,我认为虽然我对STL的一些语法有了一定的了解但是实战运用可能还是无从下手,后面的例题我也是一个个看完,每一个代码我也实际操作一遍。例题所用的一些思想还是很巧妙的,比如求最小公共倍数竟然还有“辗转相除法”这么巧妙的东西,一些思路也是出人意料的精巧。

看着书上的例题并开始做老师出的题,题大都是英文描述的,听老师说正常ACM题大都是英文题,但是读起来不难,其实虽然单词都认识最后也能读懂题意,毕竟不是中文读起来还是不能快速流畅。老师出的题好像都是书上的例题,不过我还是有的按照自己的思路又做了一边,虽然WA了好几次,但是通过问同学还是AC了,感觉STL真是个方便的东西。

然后大一下学期就开学了,因为ACM课程在本部开课而且是周末的课,所以即使是周末为了不迟到也要早起一会赶一下班车,饭就在车上解决了。这个时候天气还是比较冷的,上课的教室几乎不见阳光,也很冷。还记得老师第一节课刚开始给我们说的,如果你想按照其他选修课来上这个课肯定拿不到学分,其实我对待其他选修课也是一样的从来没缺过,和必修课一样,也是需要学的,我其实内心是很要强的即使是选修课也不能仅仅满足于及格,能往高处考就往高处考。老师希望我们能通过这个课程多多少少学到一点东西,而不是像大部分学生一样一到考试就用突击背诵来应付过去,他希望能通过这个课改变我们现在的学习方式,其实我感觉很有道理,突击应付过去了考试但自己其实没学会啥东西,我感觉是很可惜的,老师还给我们说了一些课程的评定成绩的方式。

第一节课讲了一点点STL就开始讲第一个专题——贪心算法,说实话一开始听到这个名字很纳闷贪心算法是什么,也不是和我想的一样有一个固定的套路可以套用,需要自己找贪心原则,一开始听真的是云里雾里,不明所以。这个东西和数学不一样有固定的公式可以直接死板套用,而是很灵活,这也是我往后学习才知道这些灵活的精巧之处就是算法吸引人的地方,当你不会的时候看看别人代码的思路,大呼神奇,为他人巧妙的的思想折服。因为一开始学习的时候不是很懂因此第一个专题做起来也很费劲,有点打击。向老师求助过,老师说要多看看例题,理解基本的思想。于是只能硬着头皮看了也没有其他办法,接下来的课,老师讲了几个例题渐渐明白了什么意思,也能磕磕绊绊做做几个题(大部分都是老师上课讲的题或者类似的题),其实在这种痛苦的过程中AC一道题感觉像闷热的天气吹来一阵凉风。

渐渐地,理解了贪心算法,就是依据某种贪心标准求每一步的最优解,若干次后得出整个问题的最优解。其中最难的就是贪心标准的选择,贪心标准选好了问题就会变得特别简单,其实ACM越难的部分也是它美的体现,难点解决出来的结果总是特别巧妙,典型的题型就是老师最开始讲的活动安排问题,以及背包问题,贪心算法大多都要用到sort函数,而用sort函数的时候大都要自己写排序标准函数cmp,这个就根据套路来了。贪心标准的选择也很有技巧,例如活动安排的问题,贪心标准就是谁的活动早结束就选谁,背包问题的标准一般是性价比。有时候贪心问题不能直接看出来或者直接贪心不好做,需要将问题转化,比如曾经有一道办公室搬桌子的问题,就是先把房间号映射为走廊号,看每段走廊的占用情况找出被占用最多的次数就是需要搬运的次数。还有一个是问买东西花的纸币数什么时候最少,什么时候最多。我做完第一小问就不知道第二小问最多怎么求了,我到网上看了别人的思路介绍豁然开朗,自己花的纸币最多,不就是自己手上留下的纸币最少嘛。所以看似两个问题其实就是一个问题。贪心标准的选择就是重点难点,问题转化的能力也很重要。

磕磕绊绊终于过去了贪心算法,真的有好几个题真的特难,田忌赛马那个感觉自己算法是对的不知道提交了几遍都是WA,无奈只好依据别人的贪心标准写了。接下来是第二个专题搜索,这个词听起来还可以,天天用搜索引擎嘛,刚上搜索课老师就说,这个和贪心悄悄相反,贪心是理解难做起来简单,这个搜索是理解起来简单,做起来难。并告诉我们如果以后想研究人工智能,这个搜索是基本,当然不限于这么简单,还记得当时举了李世石大战谷歌Alpha Go的例子,因为围棋模拟所有情况数据会超乎想象的大,仅仅通过简单的搜索是做不到的。不管怎么说开了新的专题,换个心情,又是从0开始学习吧!

搜索讲了4类,分级别是二分搜索,三分搜索,广度优先搜索,深度优先搜索。搜索很好理解每种情况都试一遍肯定就会有,虽然比较笨拙,但计算机是很快的。最简单的要数二分搜索了,理解起来简单做起来也基本有套路。主要针对于单调有序的集合中查找元素,具体方法就是:确定上线和下限,然后通过不断二分取中间值逐渐缩小区间,当区间上下限差足够小时就可以认为,求得了结果。而三分搜索就是转化为二分搜索来求,比较适用,当需要求某凸性或凹形函数的极值,通过函数本身表达式并不容易求解时,就可以用三分法不断逼近求解。方法就是:类似二分,先确定中间值,再用中间值和其中一个边界确定另一个中间值,之后看看mid和midmid谁更接近结果(极值),之后缩小上下限,逐步逼近。因为不论是二分还是三分都比较针对于类似数学一次二次函数模型的问题,所以如果将问题转化为数学公式表示就会简单很多,毕竟数学有数学的求解方法。有很多题可以直接转化成数学公式或者直接给出公式进行求极值的问题。

接下来就是比较复杂的广度优先搜索和深度优先搜索,其实一开始老师讲的是很简单的,但是做题还是有一些难,不知道如何表示,而且搜着搜着就容易超时,因为搜索要把所有情况列出来,有时候32位的整数存不下太大数据,因此有很多细节需要注意。广度优先搜索就是从初始状态S 开始,利用规则,生成所有可能的状态。构成的下一层节点,检查是否出现目标状态G,若未出现,就对该层所有状态节点,分别顺序利用规则,生成再下一层的所有状态节点,对这一层的所有状态节点检查是否出现G,若未出现,继续按上面思想生成再下一层的所有状态节点,这样一层一层往下展开。直到出现目标状态为止。代码中常常用queue队列容器保存状态,每次取出一个生成下一次状态,保存到队列中,把取出的状态从队列中删掉。对于深度优先搜索:从初始状态,利用规则生成搜索树下一层任一个结点,检查是否出现目标状态,若未出现,以此状态利用规则生成再下一层任一个结点,再检查,重复过程一直到不能再生成新状态节点,当它仍不是目标状态时,回溯到上一层结果,取另一可能扩展搜索的分支。采用相同办法一直进行下去,直到找到目标状态为止。

对于深搜,我的印象还是比较深刻的,印象最深的就是找油井块的那个题,也是让我认识到了搜索神奇的地方,在这个题中我学到了设置方向数组这种用法,深搜的一个特点就是需要很多条件来限制避免重复搜索提高搜索效率,一般要用一个数组来记录已经被访问过的地方,用一个函数判断是否超过搜索边界,虽然广搜的代码比较长但是理解起来不是很难,不过做题的时候自己遍就会出现诸多问题,因为细节问题需要注意的很多。深搜代码典型特点就是一般都要用到queue容器来扩展状态首先把初始值放进去,只要queue不为空就一直展开下去。

说实话搜索代码比较长而且很繁琐,重要的是捋清思路,要很缜密地思考问题,因为搜索所有情况都要遍历一边,因此很容易超时,尽量用c语言的输入输出,一不小心就超时。老师还讲了一种位运算可以有效地提升程序效率,但是我不是很懂位运算符,而且想到这种方法也很难,因为是直接对二进制进行操作,需要更加缜密的思维才行。不过当时听了还是觉得很神奇地,它可以用来判断奇偶性,还可以直接对于那些只用1和0就能表示地图的搜索问题可以很有效地提升效率。不过要是自己想的话应该是想不到,本来就对于位运算符不是很了解,再加上刚学的搜索还不扎实,用这个实在想不出来,搜索专题到最后没做的题也比贪心多,虽然好理解但做题实在不好想。

五一放假前动态规划开了个头,说实话经历了贪心和搜索的虐,开始有些疲乏了,不过有五一假期可以调整一下。

动态规划思想比较巧妙,是解决多阶段决策问题的一种方法。如果一类问题的求解过程可以分为若干个互相联系的阶段,在每一个阶段都需作出决策,并影响到下一个阶段的决策。多阶段决策问题,就是要在可以选择的那些策略中间,选取一个最优策略,使在预定的标准下达到最好的效果。说白了就是每一步都会受上一步影响并且影响下一步。老师讲的第一个例题就是最长上升子序列的问题,我又见到了一种考虑问题的方式。接下来就是五一放假啦,趁着五一看看这次的专题,发现了另一种动态规划的问题——斐波那契数列类的问题,这个特别简单就是把初值给出来之后用菲波那契数列计算方法,往后计算,输出的时候直接调用,像母牛生小牛,上楼梯的问题,都是一样的做法。于是趁着假期多做了几个这种简单题,毕竟看着AC多了心理也很愉悦。

然后就是背包问题,主要有一下几种背包,0 1背包,完全背包,多重背包。01背包就是考虑放与不放的问题,01背包有个典型的特点,代码第二重循环是从大到小遍历的。完全背包比01背包多了就是数量的问题,不仅要考虑选不选,还要考虑选多少。完全背包代码也有一个特点就是第二重循环从小到大遍历。而多重背包与完全背包的区别就是,完全背包的物品数量是无限的,而多重背包的物品数量是有限的,解决多重背包的问题通用方法就是转换为01背包或完全背包的问题。具体做法就是写三个函数分别处理完全背包,01背包,以及多重背包,在多重背包函数中,如果商品的总价值和大于背包容量转化为完全背包否则转换为01背包。动态规划代码最典型的特点就是要用数组保存每次的最优值,并用循环每次选出当前状态的最优解。因此有的问题是由相互联系的,代码有的甚至还可以重用。

到了最后一个专题图的问题,其实感觉很可惜图的问题还是比较有意思的,当然看起来也比较难,老师因为有一个星期要带队出去比赛落下了一节课,最后图的问题只讲了三节课,自己看确实没看懂过,对于自己来说我搞不懂怎样把一个图形的问题用数组用代码表示。出了专题也无从下手。

终于等到老师讲图的问题了但是光概念就讲了大半节课,最后只讲了一个例题,不过这个例题内容还是挺丰富的,包括了如何找并查集,合并并查集,然后第二次课又讲了最小生成树的问题解决了带权值的图的问题解决方法包括prim算法和Kruskal算法。之后我发现专题的前几个题都可以转化成搜索最小生成树的问题,于是一个代码用了差不多5遍左右,当时感觉很不可思议,最后一次课讲了最短路径的算法,包括bellman-ford算法spfa算法dijkstra算法floyd-washall算法,这样大部分题就都能做了。我的ACM课程也就这样结束了,但题依旧继续。

我最后没有选择继续参加ACM的集训,我并没有忘记自己选择课的初衷,真正学到点东西并且试试自己在这方面的能力,对于我个人来讲如果我投出所有时间去做ACM我心里会放心不下其他课程,因为我是个力求追求平衡的人。刚开始的时候因为老师说每个专题平均一天一道题,自己感觉时间很紧,会跟不上,一开始节奏有点乱,和其他课程总感觉时间不会分配,学习节奏和上学期完全不同,很混乱。通过一个专题的调整才渐渐适应。一个学期的学习老师讲了很多,我相信短短的一个学期并不能让我完全掌握老师讲的东西,但我从算法的身上看到了看到了各种大神算法的巧妙与精致,我相信我也真正地学到了算法的一些相关知识,开阔了我的思维,学会了一些问题的思考方式。

每次见到精巧的代码,总会感到很过瘾,憋了很久通过自己双手最后AC代码,也很兴奋的跳跃欢呼起来。我想这一段ACM课程学习的经历,一定会对我接下来的专业课程学习有所裨益。我认为大学生学习不能带着一种功利心,选修课不能因为难就不选,要多学一点对自己有益的的课程,这个学期我都选择了法律的选修课,因为我认为作为程序员自己的知识产权还是要懂一些的。就像我们班主任所说“即使是去当炮灰,也要看看别人的大炮怎么发射的。”虽然学习ACM的过程很虐,但虐得开心,看到了精致的代码收获多多,这是我学习过程中宝贵的财富。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值