算是一份学习计划

复习

基础算法:

文件类型和文件操作      高精度计算     数据排序     递推算法    递归算法   搜索与回溯算法    贪心算法   分治算法   广度优先搜索    动态规划

数据结构:

栈      队列     树     图论算法

(复习看看书,一本通过一遍,不懂多思考,算法搜博客,瞻仰神牛思路理解)

深入理解(参考了神牛九野的算法入门计划)

BFS+DFS 搜索    并查集、最小生成树、递推、同余(注意知识点:树的概念、图的概念(非常重要,请自行百度))

背包、矩阵快速幂、素数、二分查找

专题资料推荐:背包九讲,素数表的三种打发(给出一种,另一种常有的是prime[i] = true表示i为素数)矩阵快速幂模版

优先队列(最小堆)、状态压缩、单源最短路

最短路建议先学习spfa算法

 

 1     int dis[N];//N个点 此处给出邻接表写法(若不熟悉可以下拉查看邻接表的示意图)  
 2     int spfa(int start, int end, int n){//最短路的起点,终点,图的下标[1,n]  
 3         for(int i = 1; i <= n; i++)dis[i] = 100000000;  
 4         dis[start] = 0;  
 5         queue<int>q; q.push(start);   
 6         while(!q.empty()){  
 7             int u = q.front(); q.pop();  
 8             for(int i = head[u]; i!=-1; i = edge[i].next){  
 9                 int v = edge[i].to;        //遍历 以u为起点的边 的终点  
10                 if(dis[v] > dis[u]+edge[i].dis)  {  
11                     dis[v] = dis[u]+edge[i].dis;  
12                     q.push(v);  
13                 }  
14             }  
15         }  
16         return dis[end];  
17     }  

1、注意对于最短路中存在负环判定:对于spfa算法,当某个点入队列(入队列的意义就是该点被松弛了(更新))次数>n次,就说明该点在负环上(可以简单证明一个点至多被更新n次(n为图中的顶点数))。

2、优先队列:类似于堆,出队的元素不是在队尾的元素,而是队列中最小的元素(我们有时可以在队列中存储结构体元素,只需重载运算符即可)。

实例:

1 struct node{
2     int x, y;
3     bool operator<(const node&a) const
4     { if(a.x==x) return a.y<y;  return a.x<x; } //根据x,y值比较node结构体的大小
5 };

3、状态压缩:当某些状态只有true or false,时我们可以用一个整数来表示这个状态。

示例:

有3块不同的蛋糕编号1、2、3, 被老鼠啃过, 那么蛋糕只有2种状态, 我们用0表示没有被啃过, 1表示被啃过。

显然我们可以得到所有状态:000、001、010、011、100、101、110、111.

而上述二进制数对应的整数为 [0, 2^3) . (如二进制011 = 整数3表示 第2、3块蛋糕被啃过,第一块蛋糕没有被啃过)

我们可以用 for(int i = 0; i < (1<<3); i++) 来遍历所有的状态。

把多个事物的状态利用二进制含义压缩为一个整数称为状态压缩。

4、利用优先队列优化最短路时, 我们可以先出队距离起点最近的点, 则若出队的为终点显然我们已经得到了一条最短路了。

树的遍历、简单博弈、欧拉路径、Floyd算法

对于图的储存(邻接表、邻接矩阵)

简述下邻接表:

 1 struct Edge{  
 2     int to, next;  
 3 }edge[MAXN];//MAXN为边数  
 4 int head[N], edgenum;//N为点数  
 5 void addedge(int u, int v){  
 6     Edge E={v,head[u]};  
 7     edge[edgenum] = E;  
 8     head[u] = edgenum++;  
 9 }  
10 void init(){ memset(head, -1, sizeof(head)); edgenum = 0; }//注意表头的初始化 

网络流、网络流求最小割、最小割定理

1、简述一下最小割:对于一个图,我们要删除一些边使得 1点与n点不连通。

删边的费用为边权值,则总边权和就是 一个可行解的割边集的权值

当费用最小时,我们称为最小割。

最小割 = 最大流 做一个简要证明:

我们要找一个 1点和n点的最小割 边权和(这个答案是 1点到n点的最大流)

首先我们把1、n作为源点和汇点,跑一次网络流

那么对于某条流, 显然说明了这条流是 连接着1点和n点的一条路径。

这条路径我们必须去掉,当然删除这条路径上的任意一条边就可以认为去掉了这条路径。

而这条路径上的任意边 边内的流量就是 这条路径的流量

因此为了得到删除这条路径的最小费用,我们选择这条路径上满流的边(这样不会有多余的费用产生)

此时删边的费用=边权值=流量

对于每条连接着1-n的路径都这样操作, 就能得到:最大流 = 最小割

(注意以上1点和n点只是举例,可以替换为任意两点或者任意两个点集,而非具体的定义)

补充:对于上述所说的某条路径:路径上的边必然有一条或者多条是满流的。

我们可以用反证法:假设所有边都是不满流的,此时我们还可以再在这条边上增加流量直到某条边满流为止。

2、网络流的建图是重点。

1)可以通过虚拟一个源点(汇点)来限制流入(流出)整个网络的流量

比如:当源点为1时,我们用 0 作为源点 并建一条 0->1 边权为C的边,这样就能限制流入流量为C。

2)当有很多个源点时,我们也可以建一个虚拟源点来连接所有源点,这样就只有1个源点了。

3)对于某个点 i ,我们可能只允许流过C流量,则此时我们把i点拆开(就是用两个点来表示i点(比如 i 和 i+N )) 然后 i 与 i+N 中间建一条边权为C的边 来对i点限流。

3、可先学习白书的递归版dinic,然后手敲过题。

白书模版请点我。←边板子的水题请点我

各类网络流模板:http://www.notonlysuccess.com/index.php/algorithm-of-network/

完全二叉树、线段树、线段树的Lazy操作

线段树资料:http://blog.csdn.net/metalseed/article/details/8039326

线段树的应用-04国家队论文

胡浩线段树题集及代码模式:http://www.notonlysuccess.com/index.php/segment-tree-complete/

一个木有模板的专题,请多仔细阅读资料(然后刷题)

线段树学习:

0、04年国家队论文、白书

1、建议学习胡浩版的线段树(即一个节点用一个结构体来表示)

1     struct node{  
2         int l, r;  
3         int val;  
4     }tree[N*4];  

这样容易理解线段树的结构(如果不熟悉线段树的结构,可以在vs2012以上版本的编译器的单步调试中查看tree这个变量,会比较清楚地看到线段树的酷炫结构,这是帮助理解的重要一步)

本博客的线段树也是hh牛那里学习的,较容易形成模版化减少出错。

2、线段树的另一个重要功能:延迟操作

比如我们对一个数组a有2种操作

  一、区间[l,r] 每个数+ val

 二、单点求值

1 struct node{  
2     int l, r;  
3     int sum, lazy;  
4 }tree[N*4]; 

那么其实如果我们修改了1000次[1,n]区间,而在第1001次才求某点的值,那么我们不用急着把每个点更新了

而是在[1,n]这个区间做一个标记,表示这整个区间的数都被加上了一个值,那么前1000次操作都只需要对lazy修改即可。

等询问时再把这个lazy标记传到下面的区间去。

这种操作就叫延迟操作
3、线段树的延迟操作,建议写成当前区间最新,即当这个区间有lazy的标记时,这个区间也要保持最新

2-SAT、简单博弈

(注意知识点:对STL的set集合学习)

set用法简介:wenku.baidu.com/view/b71a8b524431b90d6c85c746.html

2-sat的简要在↓前面,一般可以用dfs或者tarjan缩点判断,这里暂且推荐dfs版本,较容易理解且编程复杂度不会太高。

2-sat 白书模版

字典树、KMP

字典树:一个重要特色就是省内存, 多个前缀相同的字符串只需要记录一次(言外之意:对于某节点的所有子树,他们的字符串都是有公共前缀的)

字典树资料:百度百科

字典树模版:blog.csdn.net/acmmmm/article/details/12250267

KMP个人简介(纯粹广告):blog.csdn.net/acmmmm/article/details/9863495

KMP其他资料:blog.csdn.net/yaochunnian/article/details/7059486

KMP的复杂度是线性的,即O(n+m);

关于KMP的2个版本:普通KMP的失配数组 next[0] = 0, 滑步函数优化的失配数组 next[0] = -1;

这里推荐先学习普通版本KMP,滑步函数据说速度稍快,但失去了KMP本身的含义,且普通KMP的速度对于比赛已经足够快了。

有向图的强连通分量、缩点

 强连通是对有向图求环的算法,tarjan(相当于dfs)

主要是环具有些特性,因此把环视为一个点,对图中环进行缩点,并给图重新标号

模版性较强。

强连通算法可参考白书319页 或 这里

更高端的在这里:www.byvoid.com/blog/scc-tarjan/

强连通模版

RMQ问题、LCA转RMQ、树状数组

RMQ问题:区间求最值,可以用线段树等解决; 

LCA:最近公共祖先,可以用离线的tarjan,在线的LCA转RMQ(预处理O(nlogn),询问O(1),LCA倍增法(预处理O(nlogn),询问O(logn))

模版变动不大,主要多做题。

树状数组:对于一个数组,可以区间求和,支持单点更新,复杂度均为O(logn);

拓展:树状数组的区间操作

LCA题集 

LCA倍增法模版

LCA转RMQ解法示意

数位dp、单调队列、滚动数组、费用流      差分约束(拓展(引用自点击打开链接))

乘法逆元:

(a / b)%mod  =  a * (b^(mod-2))

b^(mod-2)套个快速幂,复杂度是log(mod), 基本是一个常数。

·无向图的割顶和桥、树的重心       ·无向图的双连通分量       ·无向图的双连通分量      ·拓展欧几里德、AC自动机

·二分匹配、基数排序

二分匹配的图论相关:(1)(2

 二分匹配的定义:(1

·后缀数组       ·次小生成树、区间dp

当520走到这里时,再往前看,看以前的题和以前的自己,一定会惊讶自己走了这么远~



 

 

 

PS
原文地址:https://www.cnblogs.com/five20/p/7531905.html