acm 课程总结

ACM论文

    以前acm对我来说是一个很神秘的东西,从大一就对这个很好奇,但是对这个却不是很了解,等到真正学才知道以前的想法挺幼稚的。我记得最深的一句话就是:生死看淡,不服就干。这句话真的很提干劲,让我在没有动力的时候可以再次鼓起力气来继续刷题,刷题是一件很苦的事情,因为他占用了你很多的时间,你可能有很多作业要做,与你的acm冲突,你不得不自己加班去把失去的时间补回来,这是一件很寂寞的事情,当你周围的人在休息,在打游戏的时候你在写acm,你可能会感觉到不平衡,但你的付出肯定会有收获,在学数据结构的时候,感觉有很多熟悉的地方,学起来会很轻松,有些东西在别人看起来很困难的东西你会感觉那是小儿科一样的题目,所以成功永远总是孤独的,而我们需要的是坚持坚持再坚持,记住生死看淡,不服就干。

学acm之前我还在暑假学习了一下这门课的预备知识,关于队列等的内容,这个学习过程对我来说很新鲜,以前遇到的很困难的题好像都有了他的解法,而有一些题目我仍然解答不出,所以这激起了我对acm课程的极大兴趣。所以我也就怀着兴奋的心情开始了acm的课程。

    这个学期学的acm大体可以分为这么几个部分:

    第一部分是贪心算法的内容,这是我接触到的第一个和acm有关的算法,说实话,对我来说贪心算法真的很难懂,所以我就听课,看ppt,刷题,问同学,终于做出了第一个acm题。这个和以前学c++做的openjudge很相似 ,但是做出来的心情不一样,就像爬山一样,你怕爬了一座矮的山和爬了一件座高的山感觉是不一样的,你爬多少遍矮的山也不如爬一遍高的山看到的风景多。

贪心算法是求最优解的一种算法,顾名思义就是每一步都要贪心获得最好的一个解。  贪心算法就是根据一种贪心标准从,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解。我们从这个定义里可以看出,贪心算法不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。当我们以后遇到的问题可以同时几种方法解决,贪心算法应该是我们最好的选择之一。但是这种机会也是很少的,老师讲课的时候说过贪心算法是可遇而不可求的,遇到贪心能选择就选择了吧。用贪心也不是那么容易的,我们需要先解决两个问题(1)该题是否适合于用贪心策略求解;(2)如何选择贪心标准,以得到问题的最优/较优解。这是因为虽然贪心算法是一种很简洁的方法,对许多问题它能产生整体最优解,但不能保证总是有效,因为它不是对所有问题都能得到整体最优解。贪心算法是一种能够得到某种度量意义下的最优解的分级处理方法,通过一系列的选择得到一个问题的解,而它所做的每一次选择都是当前状态下某种意义的最好选择。即希望通过问题的局部最优解求出整个问题的最优解。

    一般算法都是有模板的,贪心算法也有他的模板。我们用贪心算法考虑问题的时候可以从如下几个方面考虑作为解题的切入点。(1)候选集合A:为了构造问题的解决方案,有一个候选集合A作为问题的可能解,即问题的最终解均取自于候选集合A。(2)解集合S:随着贪心选择的进行,解集合S不断扩展,直到构成满足问题的完整解。(3)解决函数solution:检查解集合S是否构成问题的完整解。(4)选择函数select:即贪心策略,这是贪心法的关键,它指出哪个候选对象最有希望构成问题的解,选择函数通常和目标函数有关。(5)可行函数feasible:检查解集合中加入一个候选对象是否可行,即解集合扩展后是否满足约束条件。贪心算法常见的问题有背包问题(物品不可以分割就是0-1问题,这个时候我们就需要用到后面学到的动态规划了,物品如果可以分割我们就可以用到贪心算法了)、最优装载问题、删数问题、多处最优服务次序问题等等,遇到这些问题,我们就可以使用贪心算法了。

    贪心算法学完了就是搜索算法了,对于我来说,可能搜索算法的一些内容比贪心算法更容易学一些。所以说什么是搜索算法?搜索算法是利用计算机的高性能来有目的地穷举一个问题的部分或所有的可能情况,从而求出问题的解的一种方法。搜算算法相比于单纯的枚举算法有了一定的方向性和目标性。算法是在解的空间里,从一个状态转移(按照要求拓展)到其他状态,这样进行下去,将解的空间中的状态遍历,找到答案(目标的状态)。搜索算法比较出名的两个是:广度优先算法(BFS)和深度优先搜索(DFS),这个我们见到的就比较多了,比如说数据结构上的无向图的深度优先算法和广度优先算法,在我看来树的前中后层序遍历也有搜索的影子在,所以这是一个应用很广泛的算法。那什么是广度优先搜索呢?广度优先搜索的基本思想:从初始状态S 开始,利用规则,生成所有可能的状态。构成的下一层节点,检查是否出现目标状态G,若未出现,就对该层所有状态节点,分别顺序利用规则。生成再下一层的所有状态节点,对这一层的所有状态节点检查是否出现G,若未出现,继续按上面思想生成再下一层的所有状态节点,这样一层一层往下展开。直到出现目标状态为止。如果学过树的层序算法,你会发现这俩个好像就是一回事。那什么是深度优先算法呢?深度优先搜索的基本思想:从初始状态,利用规则生成搜索树下一层任一个结点,检查是否出现目标状态,若未出现,以此状态利用规则生成再下一层任一个结点,再检查,重复过程一直到叶节点(即不能再生成新状态节点),当它仍不是目标状态时,回溯到上一层结果,取另一可能扩展搜索的分支。采用相同办法一直进行下去,直到找到目标状态为止。那这两个算法就是万能的吗?不,他们还是有各自的优缺点的:.1、深度优先算法占内存少但速度较慢,广度优先算法占内存多但速度较快,在距离和深度成正比的情况下能较快地求出最优解。2、深度优先与广度优先的控制结构和产生系统很相似,唯一的区别在于对扩展节点选取上。由于其保留了所有的前继节点,所以在产生后继节点时可以去掉一部分重复的节点,从而提高了搜索效率。3、这两种算法每次都扩展一个节点的所有子节点,而不同的是,深度优先下一次扩展的是本次扩展出来的子节点中的一个,而广度优先扩展的则是本次扩展的节点的兄弟点。在具体实现上为了提高效率,所以采用了不同的数据结构。所以我们不能盲目的就决定使用哪一个算法,我们需要对具体题目进行具体分析,看我们的内存是怎么样的,我们需要的是速度还是效率等等。这些东西都是需要我们做题熟练了才可以体会到的。

    搜索算法还有其他的算法,比如说二分查找算法,二分查找算法是在一个单调有序的集合中查找元素,每次将集合分为左右两部分,判断解在哪个部分中并调整集合上下界,重复直到找到目标元素。这个二分查找算法就是我们在数据结构中学到的折半查找算法,这种算法相比前两种算法简单了很多,用起来也感觉很舒服,比如说求个一元多次函数的解还是很好用的。

后面这个算法相比前两个就是重中之重了,这个算法是动态规划算法,我在网上看视频的时候,看到的第一个算法就是动态规划算法。动态规划是什么?动态规划是解决多阶段决策问题的一种方法。作为一个算法就必定要有他的解题模板,动态规划的解题模板是这样的:动态规划问题具有以下基本特征: 问题具有多阶段决策的特征。每一阶段都有相应的“状态”与之对应,描述状态的量称为“状态变量”。每一阶段都面临一个决策,选择不同的决策将会导致下一阶段不同的状态每一阶段的最优解问题可以递归地归结为下一阶段各个可能状态的最优解问题,各子问题与原问题具有完全相同的结构。这里面有一些概念我们需要对这个进行解释:1.阶段:据空间顺序或时间顺序对问题的求解划分阶段。2.状态:描述事物的性质,不同事物有不同的性质,因而用不同的状态来刻画。对问题的求解状态的描述是分阶段的3.决策:根据题意要求,对每个阶段所做出的某种选择性操作。4.状态转移方程:用数学公式描述与阶段相关的状态间的演变规律。动态规划的解题步骤是这样的:1、判断问题是否具有最优子结构性质,若不具备则不能用动态规划。2、把问题分成若干个子问题(分阶段)。3、建立状态转移方程(递推公式)。4、找出边界条件。5、将已知边界值带入方程。6、递推求解。动态规划的应用可以是很灵活的,比如说贪心算法,虽然贪心算法在大多数情况下都不能直接得到最优解,但是,它仍旧可以与搜索算法并用。具体有如下用处:(1)在解决某些最优化问题中,利用贪心算法在极短的时间(贪心算法的时间复杂度几乎为O(n)或O(1))内得到一组较优解。于是定出搜索的边界,可以剪去大量的分支。(2)搜索的某一个部分可以采用贪心来解决(比如说某些问题的最后几步),大大节省了搜索的时间,提高了效率。

动态规划的应用是很广的,这个我们之前也说到过,他的应用我们可以一般可分为线性动规,区域动规,树形动规,背包动规四类。我们可以很轻易的举出他们应用的例子:线性动规:拦截导弹,合唱队形,挖地雷,建学校,剑客决斗等;区域动规:石子合并, 加分二叉树,统计单词个数,炮兵布阵等;树形动规:贪吃的九头龙,二分查找树,聚会的欢乐,数字三角形等;背包问题:01背包问题,完全背包问题,分组背包问题,二维背包,装箱问题,挤牛奶等等。这些是我们在刷题中会应用到的,那实际中我们就没有用出了吗,当然不可能,一个算法的产生必然是因为我们的需求,比如说出名的最短路径问题 ,项目管理,网络流优化等;所以说这是一个很重要的算法。这对我来说做题很难也很简单,主要就是我对这个算法的了解太肤浅,遇到了简单的题我可以利用算法轻松的解答出来,遇到的难题就不知道从何处下手,所以在acm这门课结束后,我还需要继续认真深入的学习动态规划,不光是因为我需要用到这个算法,还因为我觉得动态规划对我来说就是一个挑战,我不能再这个算法面前止步。

但真正困难的地方还是在图论,说真的,到现在我明白的图论算法只有一两个,虽然说在离散数学中学过很多图论相关的知识,但放到代码里还是很难实现的,因为需要用到很多的前置知识,比如说队列什么的。为什么我们要学图论那,因为现在寻找最短的路径到达想要去的地方在这个快节奏的时代已经变得越来越重要,它对于节约人们的时间成本具有重要意义。当前城市的规模越来越大,交通道路状况也越来越复杂,从一个地方到另一个地方可能有很多种路径,如何从众多的路径中选择距离最短或者所需时间最短的路径便成了人们关注的热点。能够选择出一条最符 合条件的路径会给我们的日常生活带来极大地方便。图论中用到了很多的算法,比如说1.Prim算法1) 任意选定一点s,设集合S={s}(2) 从不在集合S的点中选出一个点j使得其与S内的某点i的距离最短,则(i,j)就是生成树上的一条边,同时将j点加入S(3) 转到(2)继续进行,直至所有点都己加入S集合。2.Kruskal算法将边按权值从小到大排序后逐个判断,如果当前的边加入以后不会产生环,那么就把当前边作为生成树的一条边。最终得到的结果就是最小生成树。并查集。Bellman-Ford算法思想的是,造一个最短路径长度数组序列dist 1 [u], dist 2 [u], …, dist n-1 [u]。其中:dist 1 [u]为从源点v到终点u的只经过一条边的最短路径长度,并有dist 1 [u] =Edge[v][u];dist 2 [u]为从源点v最多经过两条边到达终点u的最短路径长度;dist 3 [u]为从源点v出发最多经过不构成负权值回路的三条边到达终点u的最短路径长度;dist n-1 [u]为从源点v出发最多经过不构成负权值回路的n-1条边到达终点u的最短路径长度;算法的最终目的是计算出dist n-1 [u],为源点v到顶点u的最短路径长度。spfa算法其实就是Bellman-Ford的一种队列实现,减少了冗余,即松驰的边至少不会以一个d为∞的点为起点。1.队列Q={s}2.取出队头u,枚举所有的u的临边 .若d(v)>d(u)+w(u,v)则改进 ,pre(v)=u,由于d(v)减少了,v可能在以后改进其他的点,所以若v不在Q中,则将v入队。3.一直迭代2,直到队列Q为空(正常结束),或有的点的入队次数>=n(含有负圈)。一般用于找负圈(效率高于Bellman-Ford),稀疏图的最短路。

其实中间有很多次后悔选择acm这门课,但最终我坚持了下来,虽然很多次我听不懂课的内容,但是我没有放弃,我不会因为不会而不来上这门课,我会慢慢的学习,我相信笨鸟先飞。我会永远的记住那句话:生死看淡,不服就干。这不会是我acm课的结束,而是acm的开始,i will be the winner

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值