2014-7月~2014-10月总结

来源:互联网 发布:老炮儿 网络剧 编辑:程序博客网 时间:2024/04/24 20:50

从7月份到现在,经过这三个月的训练学习,我的收获其实挺多的,也掌握了不少新的基础的算法,所以今天就在这总结一下:

等等,我先说明一下:动态规划和搜索,这两个最基础但是也是最最重要的算法,我自以为还没有吃透,所以在此就不做总结了,但会在这两周快速消化,并总结出来。

一、我先学习了各种排序算法:包括冒泡排序,选择排序,插入排序,双向冒泡排序, 桶排序,堆排序,希尔排序,快速排序,归并排序;

但是学习之后发现,真正在比赛中考到的其实无非就是快速排序,堆排序,归并排序。堆和归并其实也少,但也会用到,一定要掌握,因为有一些题目会故意卡快排。倒也不是说,冒泡,选择那些学了没用。比如有的题,用插入排序对数据微调整就是要比用快排,归并什么的重排效率高,还有一些简单题,没必要打什么归并的,一个冒泡打出去照样解决,还很简单。而且老话说的好:技多不压身。会了总比不会强很多,而且这也是最基础的,都必须掌握。

接下来,我就来总结一下代码(主要是快排和归并)

1、快排

快速排序是冒泡排序的一种改进。它的基本思想是:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。快速排序的时间复杂度是O(nlogn),速度快,但它是不稳定的排序算法。就平均时间而言,快速排序时目前被认为是最好的一种内部排序方法。
2、归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。

其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了?

可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。

3、sort函数

这个函数就是简单版的快排,有了这个函数,就不用再打代码了

二、高精度算法
高精度算法其实很好理解,完全就是一个竖式计算的模拟,所以原理什么的不用多说,直接上代码
首先我们需要将读进来的字符串转化成数组储存
1、加法
2、减法
3、乘法
4、除法
(1)高精除以低精
   
(2)高精除以高精
   
三、并查集
     

并查集

维护一些不相交的集合,它是一个集合的集合。每个元素恰好属于一个集合,好比每条鱼装在一个鱼缸里。每个集合S有一个元素作为集合代表"rep[S],好比每个鱼缸选出一条"鱼王"。并查集提供三种操作:

MakeSet(x):建立一个新集合x。x应该不在现有的任何一个集合中出现。
Find(S, x):返回x所在集合的代表元素。
Union(x, y):把x所在的集合和y所在的集合合并。

森林表示法

可以用一棵森林表示并查集,森林里的每棵树表示一个集合,树根就是集合的代表元素。一个集合还可以用很多种树表示,只要树中的结点不变,表示的都是同一个集合。

合并操作

只需要将一棵树的根设为另一棵即可。这一步显然是常数的。一个优化是:把小的树合并到大树中,这样会让深度不太大。这个优化称为启发式合并.

查找操作

只需要不断的找父亲,根就是集合代表。一个优化是把沿途上所有结点的父亲改成根。这一步是顺便的,不增加时间复杂度,却使得今后的操作比较快。这个优化称为路径压缩。

代码:

四、最短路
(1)spfa算法

    SPFA(Shortest Path Faster Algorithm)Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算。

算法大致流程是用一个队列来进行维护。 初始时将源加入队列。 每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。 直到队列为空时算法结束。

设Dist代表S到I点的当前最短距离,Fa代表S到I的当前最短路径中I点之前的一个点的编号。开始时Dist全部为+∞,只有Dist[S]=0,Fa全部为0。

维护一个队列,里面存放所有需要进行迭代的点。初始时队列中只有一个点S。用一个布尔数组记录每个点是否处在队列中。

每次迭代,取出队头的点v,依次枚举从v出发的边v->u,设边的长度为len,判断Dist[v]+len是否小于Dist[u],若小于则改进Dist[u],将Fa[u]记为v,并且由于S到u的最短距离变小了,有可能u可以改进其它的点,所以若u不在队列中,就将它放入队尾。这样一直迭代下去直到队列变空,也就是S到所有的最短距离都确定下来,结束算法。若一个点入队次数超过n,则有负权环。

改进: 1、第二步,不是枚举所有节点,而是通过队列来进行优化 设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。 2、同时除了通过判断队列是否为空来结束循环,还可以通过下面的方法: 判断有无负环:如果某个点进入队列的次数超过V次则存在负环(SPFA无法处理带负环的图)。

(2)Floyd算法

1)算法思想原理:

     Floyd算法是一个经典的动态规划算法。用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径。从动态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在)

      从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

2).算法描述:

a.从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。   

b.对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。


以上就是这段时间真正掌握的,看起来好少的样子,不过没关系,这类题只要出现我差不多就能做对。另外这段时间我还学了搜索,状态压缩DP,树形DP,线段树,树状数组,只是这几类做题太少,或者说并没有完全理解,所以这次总结就没有把他们算在内。接下来两周(就是NOIP之前),在做往年NOIP题的同时,我还会继续深入的学习上面集中算法,吃透弄熟,备战NOIP2014。
















0 0
原创粉丝点击