算是一份学习计划
复习
基础算法:
文件类型和文件操作 高精度计算 数据排序 递推算法 递归算法 搜索与回溯算法 贪心算法 分治算法 广度优先搜索 动态规划
数据结构:
栈 队列 树 图论算法
(复习看看书,一本通过一遍,不懂多思考,算法搜博客,瞻仰神牛思路理解)
深入理解(参考了神牛九野的算法入门计划)
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版本,较容易理解且编程复杂度不会太高。
字典树、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);
拓展:树状数组的区间操作
数位dp、单调队列、滚动数组、费用流 差分约束(拓展(引用自点击打开链接))
乘法逆元:
(a / b)%mod = a * (b^(mod-2))
b^(mod-2)套个快速幂,复杂度是log(mod), 基本是一个常数。
·无向图的割顶和桥、树的重心 ·无向图的双连通分量 ·无向图的双连通分量 ·拓展欧几里德、AC自动机
·二分匹配、基数排序
二分匹配的定义:(1)
·后缀数组 ·次小生成树、区间dp
当520走到这里时,再往前看,看以前的题和以前的自己,一定会惊讶自己走了这么远~