第二十六天总结

今年暑假为了提高我们的编程能力,同时也是为了以后的ACM程序设计大赛,我们三十多位同学在一起参加了本校的ACM暑期集训。在短暂的二十多天中,我们在一起为了我们共同的目标,在相同的兴趣下一起训练,一起学习,在这当中我们学到了很多,也提高了很多。
这次集训主要是上学期ACM程序设计课程为引子,逐渐走向程序设计大赛的道路。有的同学选择在家训练,我更喜欢学校。原来都是为了切题而切题,很多东西并没有真正弄懂,暑假集训给我的一个最深刻的总结就是,题做的多你不一定强,做的少也不一定弱,只有你真正懂得这一个知识点一个算法,能够弄通一道经典题,比做十几道要管用很多。书和博客都要多看,在这些方面我还是有些欠缺。理论和动手一定要在一块,实践不懂的就请教别人或者继续看书,在这样不断的循环之下,自己才能学到东西,提高自己的能力。
集训的内容主要分为六项,其中一项是比赛,另外的都是学习新的知识或巩固旧的知识。旧的知识主要是深度优先搜索,广度优先搜索,动态规划,最短路径,最小生成树,二分法。新的知识主要是一些数据结构,树状数组,单调队列,线段树。还有就是我在闲暇时候看了一点Linux和Python,JAVA更深入地看了一下,还学了一下怎么用Vim。因为以后比赛中知识点可能要分工,我觉得动态规划比较有感觉,就先看了一些区间dp,状态压缩dp两种,虽然不是特别熟练,基本内容都看了,题目练习还没有跟上。
下面讲一下我的总结:
一•深度优先搜索和广度优先搜索
两种搜索是非常常用的,也是各种图论算法,与数据结构的基础,但是有时候在比赛中往往由于过高的时间复杂度而超时,这时候就需要优化,剪枝是最需要的,也可以通过数据结构优化比如邻接表和邻接矩阵。剪枝有三种策略:1)微观方法:从问题本身出发,发现剪枝条件2)宏观方法:从整体出发,发现剪枝条件。3)注意提高效率,这是关键,最重要的。剪枝策略就是寻找过滤条件,提前减少不必要的搜索路径。枝条不是爱剪就能剪的。如果随便剪枝,把带有最优解的那一分支也剪掉了的话,剪枝也就失去了意义。所以,剪枝的前提是一定要保证不丢失正确的结果。有时候会出现不剪枝提交AC,剪枝之后反而WA。在这里,剪枝有三个原则正确、准确、高效原则。我个人感觉,在做题目的时候我们最应该保证正确性,尽量做到准确性。除非特殊的题目,很少有要求找出所有剪枝的,最后要求高效性,剪枝的判断不能太多,否则得不偿失跟没优化过一样。我们剪枝主要两种方法一种可行性剪枝,一种最优性剪枝。可行性剪枝是判断继续搜索能否得出答案,如果不能直接回溯,这种剪枝往往是在题目中寻找条件,有直接条件或通过推导得出一个条件。最优性剪枝通过记录结果,如果当前结点已经无法产生比当前最优解更优的解时,则提前回溯。
不同点:
深度优先搜索:利用栈这种数据结构来实现(利用递归便于实现,但是效率较低),找到的第一个解不一定是最优解,只是先序遍历最早的可行解。
广度优先搜索:利用队列这种数据结构来实现,找到的第一个解经常都是最优解(如迷宫的最短路径),但是不常用来求所有解(重复的次优解常常都被剪枝剪掉了)。
二•图论算法
这里分为三大部分,一部分单源最短路径算法,一部分多源、无负权边的最短路,最后一部分是最小生成树。图主要有3种常用的存储表示方式:邻接矩阵,邻接表,邻接多重表。
单源最短路径算法:
Bellman-Ford 算法:
对于带权有向图 G = (V, E),Dijkstra 算法要求图 G 中边的权值均为非负,而 Bellman-Ford 算法能适应一般的情况(即存在负权边的情况)。一个实现的很好的 Dijkstra 算法比 Bellman-Ford 算法的运行时间要低。这个算法采用动态规划设计,实现的时间复杂度为 O(V*E),其中 V 为顶点数量,E 为边的数量。
Dijkstra算法:
Dijkstra算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。千万注意该算法要求图中不存在负权边。Dijkstra 算法采用贪心算法进行设计,普通实现的时间复杂度为 O(V2)。有时候这个算法也会面临超时的问题,这时候一般用堆来优化,但是代码写起来比较麻烦,我一般也不会做。
SPFA:
几乎所有的最短路算法其步骤都可以分为两步1.初始化2.松弛操作。SPFA是Bellman-Ford用队列优化的算法。SPFA算法通过维护一个队列,使得一个节点的当前最短路径被更新之后没有必要立刻去更新其他的节点,从而大大减少了重复的操作次数。

求多源、无负权边的最短路:
Floyd算法:
Floyd-Warshall算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。

最小生成树:
给定一个无向图,如果它的某个子图中任意两个顶点都互相连通并且是一棵树,那么这课树就叫做生成树.如果边上有权值,那么是的边权和最小的生成树叫做最小生成树
Prim算法:
它是从点的方面考虑构建一颗MST,大致思想是:设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V以此类推。这个算法本质上也是一种贪心。
Kruskal算法:
从边的方面出发,在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边。本质也是贪心。
Prim算法适用于稠密图,Kruskal算法适用于稀疏图。但在平常中我一般选择Prim,因为编写比较方便。
三•数据结构
单调队列:
单调队列,就是一个符合单调性质的队列,它同时具有单调的性质以及队列的性质。它的作用很简单,就是为了维护一组单调数据,让我们在运行的过程中能够快速寻求前k个或后k个中最大或最小的值。至于单调栈,相信看完上面的叙述后,都会有一个大概的理解,单调栈就是一个符合单调性质的栈它同时具有单调的性质以及栈的性质。这种数据结构一般用来优化dp,比如多重背包,LIS之类的dp题目。
树状数组:
树状数组的时间复杂度比较低,修改和查询都是O(log(n)),看到这个复杂度就不禁想到了二分,没错树状数组的效率来自于巧妙的二分,还有位运算的应用。树状数组的应用非常广泛,虽然不如线段树广,但是我觉得比线段树好用。树状数组可以和很多别的算法结合,进行优化,比如dp,二分之类的。自身的题目有二维树状数组,离线化处理,离散化,高精度,求逆序等。还有就是注意树状数组是从从c[1]开始,c[0]这个元素不可以使用。
还有一些关于OJ编译器的问题都在我的博客里,在此不再赘述,有的地方限于篇幅没有详细展开说实现原理和优化方案。
紧张的集训快告一段落了,我还有一个重要的收获就是团队合作的重要性,ACM是一项团体赛个人能力固然重要,好的合作能发挥我们更大的能力。虽然我没有像其他同学一样在社会上去实践,但我在实验室里收获并不会比别的同学要少。说实话ACM是很枯燥的,只有你自己觉得好玩,有意思你才能学下去。这也让我明白,很多事情你可以没有天赋,但是如果你连兴趣也没有,一般都是一事无成的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值