ACM的暑假集训结束了,趁着军训还没开始,对整个暑假接触到的东西作了一个总结,因为刚参加ACM不久,所以内容大都比较基础吧,文章中提到了些参考资料,如果需要的话,请留下邮箱。

目录
1)数据结构
 1.并查集
 2.高精度数
 3.线段树
 4.字典树<未完成>
2)常用算法
 1.递推
 2.动态规划
 3.贪心
 4.搜索
3)图论部分  1.2-SAT问题
 2.差分约束系统
 3.二分图
 4.最短路(SPFA,Dijkstra)
 5.欧拉回路<未完成>
 6.最优比率生成树
 7.关键路径
 8.网络流(流的算法/应用)
  最大流算法(3种)
  最小费用最大流算法
  图的连通性(最小点割集)<未完成>
  混合欧拉回路
 9.其他图论相关问题算法:
  K短路
  图的单向连通(包括2次DFS缩点)
4)其他
 1.计算几何
 2.数学(数论,组合数学,数值计算)
5)附录
 1.A*算法
 2.位运算之格雷码:
 3.线性同余方程

一.数据结构:

1.并查集.

用于实现合并与查找两种操作的数据结构.
实现方法:线形数组,有根树.
优化:
把深度小的树合并到深度大的树,深度相等时任选一棵树,既max(h1,h2), if h1<>h2. / h1+1, if h1=h2.
合并操作时的路径压缩.
并查集的偏移向量:
并查集的偏移向量属于并查集的变形,只要适用于集合数目较少,或是固定的并查集类型。
增加一个offset字段,表示元素相对根的偏移量.

在find函数中计算偏移量
int findset ( int x )
{
    int t ;
    if ( father [ x ] == x ) return x ;
    else t = findset( father [ x ] ) ;
    offset [ x ] = ( offset [ x ] + offset [ father [ x ] ] ) % DEPTH ;//DEPTH表示几个状态量
    //如果1182中,DEPTH=3;
    father [ x ] = t ;
    return t ; 
}//使用函数递归调用查找父亲在处理上优于循环。
union函数中计算偏移量
void union(int x,int y,int d){
    int fx , fy ;
    fx = find ( x ) ;
    fy = find ( y ) ;
    if ( fx == fy ) return ;
    father [ fx ] = fy ;
    offset [ fx ] = (offset [ y ] - offset[x]+d+3)% 3 ;
} 

2.高精度数

大数的加减乘除
小数的高精度计算参考pku1001

3.线段树

一棵二叉树,记为T (a,b),参数a,b表示该节点表示区间[a,b]。区间的长度b-a记为L。递归定义T[a,b].
线段树能在O(logL)的时间内完成一条线段的插入、删除、查找等工作。
应用举例

求面积:  
    1) 坐标离散化  
    2) 垂直边按x坐标排序  
    3) 从左往右用线段树处理垂直边,累计每个离散x区间长度和线段树长度的乘积  
求周长:  
    1) 坐标离散化  
    2) 垂直边按x坐标排序, 第二关键字为入边优于出边  
    3) 从左往右用线段树处理垂直边,在每个离散点上先加入所有入边,累计线段树长度变化值,再删除所有出边, 累计线段树长度变化值  
    4) 水平边按y坐标排序, 第二关键字为入边优于出边  
    5) 从上往下用线段树处理水平边,在每个离散点上先加入所有入边,累计线段树长度变化值,再删除所有出边, 累计线段树长度变化值  

参考资料: segment_tree.pdf

4.字典树

用于多字符串匹配
加入KMP算法思想成为AC自动机.

二.常用算法

1.递推

寻找f(n)与f(m)的关系
经典问题:
 约翰夫环的递推公式.
 fib数(矩阵乘快速计算法)
 参考<具体数学>第一章

2.动态规划

重叠子问题较多的问题
记录重叠子问题解得解
子状态的确定与状态转移函数.

3.贪心

在对问题求解时,总是作出在当前看来是最好的选择。也就是说,不从整体上加以考虑,它所作出的仅仅是在某种意义上的局部最优解(是否是全局最优,需要证明)。
注意:若要用贪心算法求解某问题的整体最优解,必须首先证明贪心思想在该问题的应用结果就是最优解!

4.搜索

广度优先搜索,深度优先搜索。
双向广度优先搜索
启发试搜索(A*)(详细见附录部分)
搜索的减枝与优化
参考资料: 搜索算法全集.pdf / 搜索.ppt / 启发式搜索.doc

三.图论部分

1. 2-SAT问题

设 $B=\{b1,b2…bn\}$ 为一个有限布尔集变量,$\hat{B}=\{b1,b2,…bn,!b1,!b2,…,!b_n\}$.(!为取反)

设$B'$为$\hat{B}$的非空子集,定义$\vee B'=\vee{b\in B'}b$,对于给定的$B1’,B2’…Bm’\subset B’$,求B,使得等式: $(\vee B1')\wedge(\vee B2')\wedge...\wedge(\vee B_m')=1$ 成立,称为适应性问题,简称SAT。
当对给定的$\{Bm'\}$,如果$max\{|Bx'|\}=k$,我们就把这个问题称为k-适定性问题,简称k-SAT。
可以证明,当时,k-SAT是NP完全的。
2-SAT解法:构图法,对每个bx,!bx,都对应图中一个节点,共2n个节点,每个逻辑关系表示一条边,如pku2723:

1)对于一组相互排斥的钥匙 x,y,只能选一把,所以x &y==0.即 x —> ~y , y —> ~x.。  
2)对于门,因为必须打开所以 x|y==1. 即 ~x—> y , ~y—> x

参考资料:sat2_sjtu_zhaoshuang.pdf / 2-SAT.PPT

2.差分约束系统

比如有这样一组不等式:

X1 - X2 <= 0
X1 - X5 <= -1
X2 - X5 <= 1
X3 - X1 <= 5
X4 - X1 <= 4
X4 - X3 <= -1
X5 - X3 <= -3
X5 -X4 <= -3

全都是两个未知数的差小于等于某个常数(大于等于也可以,因为左右乘以-1就可以化成小于等于)。这样的不等式组就称作差分约束系统。
构图法:利用最短路中的三角不等式,即:d(v)-d(u)<=w(u,v),每个未知数对应一个顶点,每个不等式对应一条边,(将xi-xj<=c变为权值为c的边vi->vj),最后在图上求一次最短路,则所有不等式都会满足, 图中的源点可以任意选择.也可建立一个x0作为源点.x0的相关性质可以任意设置.
参考资料: 差分约束系统.doc

3.二分图

二分图又称作二部图,是图论中的一种特殊模型。
设G=(V,{R})是一个无向图。如顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属两个不同的子集。则称图G为二分图。
给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem) 如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配。 #### 匈牙利算法: 不断寻找增广路经,其核心是DFS。

bool path (int u)
{
    sx [u] = true;
    for (int v = 0; v < n; v ++){
        if (!sy [v] && lx[u] + ly [v] == weight [u] [v])
        {
            sy [v] = true;
            if (match [v] == -1 || path (match [v]))
            {
                match [v] = u;
                return true;
            }
        }
    }
    return false;
}

对每个顶点求一次增广路经即可。(可以证明,如果某次从某个顶点出发可以找到一条增广路经,则以后不可能再该定点找到增光路经,而如果某个定点出发找到了增广路经,则该店就成为路经中的点) 注:如果边上带权的话,找出权和最大的匹配叫做求最佳匹配。 #### KM算法: * 设M是一个带权完全二分图G的一个完备匹配,给每个顶点一个可行顶标(第i个x顶点的可行标用lx[i]表示,第j个y顶点的可行标用ly[j]表示),如果对所有的边(i,j) in G,都有lx[i]+ly[j]>=w[i,j]成立(w[i,j]表示边的权),且对所有的边(i,j) in M,都有lx[i]+ly[j]=w[i,j]成立,则M是图G的一个最佳匹配。
步骤:
(1)初始化可行顶标的值(l(x) =max w(x,y),l(y) = 0
(2)用匈牙利算法寻找完备匹配
(3)若未找到完备匹配则修改可行顶标的值(根据最后一次不成功的寻找交错路的DFS,取所有i被访问到而j没被访问到的边(i,j)的lx[i]+ly[j]-w[i][j]的最小值d。将交错树中的所有左端点的顶标减小d,右端点的顶标增加d。)
(4)重复(2)(3)直到找到相等子图的完备匹配为止
优化:设slack[j]表示右边的点j的所有不在导出子图的边对应的lx[i]+ly[j]-w[i][j]的最小值,在find过程中,若某条边不在导出子图中就用它对相应的slack值进行更新。然后求只要用O(N)的时间找到slack中的最小值就可以用其调整权值了。(代码参考code/图/KM2)
复杂度:优化前O(N3),优化后O(N2)
参考资料:二分图匹配.ppt

4.最短路(SPFA,Dijkstra)

SPFA算法可以处理负边。dij算法中每条边的最短路径值仅会受到在层次图中层次小于它的点影响,确定后不会改变,SPFA没有这些特点,所以可以通过多次迭代确定最短路。
参考资料:SPFA与Dijkstra,doc

5.欧拉回路

Fleury算法
 (1)任取v0∈V(G),令P0=v0.
 (2)设Pi=v0e1v1e2…eivi已经行遍,按下面方法来从E(G)-{e1,e2,..,ei}中选取ei+1:
   (a)ei+1与vi相关联;
   (b)除非无别的边可供行遍,否则ei+1不应该为Gi=G-{e1,e2,...,ei}中的桥。
 (3)当(2)不能再进行时,算法停止。
连环法(未完成)

6.最优比率生成树

概念:
有带权图G, 对于图中每条边e[i], 都有ci\和d[i](花费), 我们要求的是一棵生成树T, 它使得有:∑(c[i]) / ∑(d[i]), i∈T最大(或最小).
0-1分数规划解法:

r=cx/dx (c,d,x都是向量) ,求最小的r,设为r*  
z=cx-l*dx(1)把它的最小值记为z(l),对一个确定的l解释以lc-d为权的最小生成树.  
若z(r*)<0;存在一组x使r*>cx/dx,与r*是cx/dx的最小值矛盾.  
若z(r*)>0,不可能,因为有一组x*使r*=cx*/dx*,把这组x代入(1)得0,必有最小值<=0  
所以z(r*) == 0;
z(l)递减  
按上述二分查找计算  

参考资料:最优比率生成树.doc

7.关键路径

整个工程完成的时间为:从有向图的源点到汇点的最长路径。
“关键活动“指的是:该弧上的权值增加 将使有向图上的最长路径的长度增加。
解法:DP递推

“事件(顶点)“的最早发生时间 ve(j) = 从源点到顶点j的最长路径长度;  
“事件(顶点)“的最迟发生时间 vl(k) = 从顶点k到汇点的最短路径长度;  
假设第 i 条弧为   
则 对第 i 项活动言  
“活动(弧)“的 最早开始时间 e(i) = ve(j);  
“活动(弧)“的 最迟开始时间 l(i) = vl(k)-dut();  
状态转移方程  
    ve(k) = Max{ve(j) + dut()}  
    vl(j) = Min{vl(k) - dut()}  
解:  
    e(i) = ve(j);  
    l(i) = vl(k) - dut();  

8.网络流(流的算法/应用)

最大流算法(3种)
1. 基本最大流算法 --- Edmonds-Karp算法O(VE2)
  通过DFS每次寻找最短的增广路径增流。核心BFS。
2. Dinic算法 O(V2E) BFS建立层次网络,DFS找增广路经增幅.
  BFS 寻找终点太慢,而 DFS 又不能保证找到最短路径。1970年 Dinic 提出一种思想,结合了 BFS 与 DFS 的优势,采用构造分层网络的方法可以较快找到最短增广路,此算法又称为阻塞流算法 (Blocking Flow Algorithm)。
  首先定义分层网络 AN(f)。在残量网络中从源点 s 起始进行 BFS,这样每个顶点在 BFS 树中会得到一个距源点s 的距离 d,如 d(s) = 0,直接从 s 出发可到达的点距离为1,下一层距离为2...。称所有具有相同距离的顶点位于同一层,在分层网络中,只保留满足条件 d(i) + 1 = d(j) 的边,这样在分层网络中的任意路径就成为到达此顶点的最短路径。
  Dinic 算法每次用一遍 BFS 构建分层网络 AN(f),然后在 AN(f) 中一遍 DFS 找到所有到终点 t 的路径增广;之后重新构造 AN(f),若终点 t 不在 AN(f) 中则算法结束。
3. ISAP O(VE2)
  通常的SAP类算法在寻找增广路时总要先进行 BFS,BFS 的最坏情况下复杂度为 O(E) ,这样使得普通SAP类算法最坏情况下时间复杂度达到了 O(VE2)。为了避免这种情况,Ahuja和Orlin 在1987年提出了Improved SAP算法,它充分利用了距离标号的作用,每次发现顶点无出弧时不是像 Dinic 算法那样到最后进行 BFS,而是就地对顶点距离重标号,这样相当于在遍历的同时顺便构建了新的分层网络,每轮寻找之间不必再插 入全图的BFS操作,极大提高了运行效率。国内一般把这个算法称为SAP,显然这是不准确的,毕竟从字面意思上来看 E-K 和 Dinic 都属于 SAP,我还是习惯称为 ISAP 或改进的 SAP 算法。
  与 Dinic算法不同,ISAP中的距离标号是每个顶点到达终点t的距离。同样也不需显式构造分层网络只要保存每个顶点的距离标号即可。程序开始时用一个反向BFS初始化所有顶点的距离标号,之后从源点开始,进行如下三种操作:

(1)当前顶点i为终点时增广
(2)当前顶点有满足 dist[i] = dist[j]+1的出弧时前进 
(3) 当前顶点无满足条件的出弧时重标号并回退一步。整个循环当源点s的距离标号dist[s] >= n 时结束。    

注:对i点的重标号操作可概括为:dist[i] = 1 + min{dist[j] : (i,j)属于残量网络Gf}。
实现代码见code/图/最大流多种实现-1273
*最小费用最大流算法:每次增广所有路径中单位费用和最小的一条即可。
*图的连通性(最小点割集)
*构图求最大流:(未完成)
*混合欧拉回路
*构图求最大流:(关键:欧拉回路存在的条件是每个个点的入度等于出度)
  把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度=出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以2,得x。也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出=入。如果每个点都是出=入,那么很明显,该图就存在欧拉回路。
  现在的问题就变成了:我该改变哪些边,可以让每个点出=入?如下构造网络流模型:
  首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定向了吗?定的是什么向,就把网络构建成什么样,边长容量上限1。另新建s和t。对于入 > 出的点u,连接边(u, t)、容量为x,对于出>入的点v,连接边(s, v),容量为x(注意对不同的点x不同)。之后,察看是否有满流的分配。有就是能有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非0(上限是1,流值不是0就是1)的边反向,就能得到每点入度 = 出度的欧拉图。由于是满流,所以每个入出的点,都有x条边进来,将这些进来的边反向,OK,入=出了。对于出> 入的点亦然。那么,没和s、t连接的点怎么办?和s连接的条件是出>入,和t连接的条件是入<出,那么这个既没和s也没和t连接的点,自然早在开始就已经满足入=出了。那么在网络流过程中,这些点属于“中间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反向之后,自然仍保持平衡。
代码:code图1637

9.其他图论相关问题算法:

  1. K短路
    A*搜索,搜索到终点K次时走的路径函数:
    f(x)=h(x)+g(x) h(x)--点离目标点的距离(估计值)
    g(x)--点离起点的距离(确定值)估计值可用反向dij得到的值代替,也可以跟据情况用其他值估计。
    代码:code图244
  2. 图的单向连通(包括2次DFS缩点)
    判断途中任意两点是否存在至少一条通路.
    如果把句子“either go from x to y, or from y to x.“改为“both go from x to y, and from y to x.“则题意即为求证图是否为强连通图。求强连通图的方法有很多,最简单的是从点v开始,正向floodfill一遍,反向floodfill一遍,然后其交集即为包含点v的最大强连通子图。
    然而这道题要求判断的是是否为单向连通图,即对于任意两点u,v,要么存在路径从u到v,要么存在路径从v到u。
    首先,强连通图肯定是单向连通图,但是反之不然。
    其次,如果图中不存在任意一对双向连通的点,则该图肯定是有向无环图。考虑该图的拓扑序,则若存在序u>v,必说明存在一条路从u到v。如果上图还是单向连通图,说明任意两点都有序,则由有向无环的性质,该序可以唯一确定。则依该序排序图中所有点,结果必然唯一。即存在一条路,从某个点出发,到另一个点截止,中间经过所有的结点。
    所以,只要把图中所有的最大强连通子图都找出来,并且各自缩为单一点。这样重构的图要么是一个点,要么是有向无环图。后者的话,做一次拓扑排序,只要在某一刻存在两个以上的点入度为0的话就判错;其他情况都判对。
    代码:code图2728
    缩点可参考 code图2443

四.其他

1.计算几何

注意模板的使用与精度问题
凸包问题
直线,点的各种关系的计算
点乘与叉乘

2.数学(数论,组合数学,数值计算)

数论:质数问题,分解因素,模预算,中国剩余定理(见附录),进制转换
组合数学:容斥定理,雀巢定理,Catalan number
数值计算:二分法(f(x)=0) ,迭代法(g(x)=x)

五.附录

1.A*算法

在启发式搜索中,对于每个状态 x,启发函数 f(x) 通常是这样的形式:
f(x) = g(x) + h(x)
其中 g(x) 是从初始状态走到 x 所花的代价;h(x) 是从 x 走到目标状态所需要的代价的估计值。
相对于 h(x),还有一个概念叫h*(x),表示从x走到目标状态所需要的实际最小代价(当然,这个值有时我们是事先无法知道的)。
如果在你的启发函数里,能保证 h(x) <= h*(x),也就是说,你不能高估了从 x 走到目标状态所需要的代价,那就可以说这个搜索是 A* 算法(这里的*,英文就读作 star)。
A* 算法的特点是,如果存在从初始状态走到目标状态的最小代价的解,那么用 A* 算法搜索时,第一个找到的解就一定是最小代价的。这就是所谓的可采纳(admissible)。
例:求前 K 短的 可以带环的 路径(的长度)
1.1. 典型的启发式搜索
设起点为 s;终点为 t;对于一个点 v,dt(v) 表示从 v 走到 t 的最短路径的长度(可以在初始化的时候全都算好)。
网友 richard 教会了我,可以用最典型的启发式搜索来解这个问题。一个状态 x 表示的是从s走到某个点的一条路径,把这个点记作 x.v,把这条路径的长度记作 x.len。接着,我们可以使用以下启发函数:
g(x) = x.len; h(x) = dt(x.v);
∴ f(x) = g(x) + h(x) = x.len + dt(x.v)
初始状态中, x.v = s; x.len = 0。然后每次让优先队列(所谓的 Open 表)中 f(x) 值最小的状态 x 出队,再跟据图中所有从 x.v 出发的边发展下一层状态,让它们进队列。优先队 列中不存在判重复的问题,因为每个状态所代表的路径肯定是不一样的。
不难想通,这是一个 A* 算法,因为这里的 h(x) 本身就是 h*(x),当然满足 h(x) <= h*(x)。因此可以说,在每次出队列的状态 x 中,第一次遇到 x.v == t 时,就找到了从s到t的第一短的路径,它的长度就是f(x)...第 k 次遇到 x.v == t 时,就找到了从s到t的第k 短的路径。
http://zone.emsky.net/?uid-2-action-viewspace-itemid-118 A*寻路.

2.位运算之格雷码:

这种遍历顺序作为一种编码方式存在,叫做Gray码(写个中文让蜘蛛来抓:格雷码)。它的应用范围很广。比如,n阶的Gray码相当于在n维立方体上的Hamilton回路,因为沿着立方体上的边走一步,n维坐标中只会有一个值改变。再比如,Gray码和Hanoi塔问题等价。Gray码改变的是第几个数,Hanoi塔就该移动哪个盘子。比如,3阶的Gray码每次改变的元素所在位置依次为1-2-1-3-1-2-1,这正好是3阶Hanoi塔每次移动盘子编号。如果我们可以快速求出Gray码的第n个数是多少,我们就可以输出任意步数后Hanoi塔的移动步骤。现在我告诉你,Gray码的第n个数(从0算起)是n xor (n shr 1),你能想出来这是为什么吗?先自己想想吧。
下面我们把二进制数和Gray码都写在下面,可以看到左边的数异或自身右移的结果就等于右边的数。

二进制数 Gray码    
000 000    
001 001    
010 011    
011 010    
100 110    
101 111    
110 101    
111 100    

从二进制数的角度看,“镜像“位置上的数即是对原数进行not运算后的结果。比如,第3个数010和倒数第 3个数101的每一位都正好相反。假设这两个数分别为x和y,那么x xor (x shr 1)和y xor (y shr 1)的结果只有一点不同:后者的首位是1,前者的首位是0。而这正好是Gray码的生成方法。这就说明了,Gray码的第n个数确实是n xor(n shr 1)。
今年四月份mashuo给我看了这道题,是二维意义上的Gray码。题目大意是说,把0到2^(n+m)-1的数写成2^n*2^m的矩阵,使得位置相邻两数的二进制表示只有一位之差。答案其实很简单,所有数都是由m位的Gray码和n位Gray码拼接而成,需要用左移操作和or运算完成。完整的代码如下:

var x,y,m,n,u:longint;    
begin    
    readln(m,n);    
    for x:=0 to 1 shl m-1 do begin    
    u:=(x xor (x shr 1)) shl n; //输出数的左边是一个m位的Gray码    
    for y:=0 to 1 shl n-1 do    
        write(u or (y xor (y shr 1)),&#8217; &#8216;); //并上一个n位Gray码    
        writeln;    
    end;    
end.    

3.线性同余方程

问题简单来说就是 a = ai (mod ni) 求未知数a。
以下小结略去证明, 只是对定理作了必要的解释, 要了解相关定理,可查阅数论资料.
中国余数定理:
设 n=n1*n2...nk, 其中因子两两互质.有: a---(a1,a2,...,ak), 其中ai = a mod ni, 则a和(a1,a2,...,ak)关系是一一对应的.就是说可以由 a求出(a1,a2,...,ak),也可以由(a1,a2,...,ak)求出a。
推论1:
对于 a=ai (mod ni) 的同余方程,有唯一解
下面说说由(a1, a2, ..., ak)求a的方法:
定义 mi = n1*n2*...nk / ni; ci = mi(mf mod ni); 其中 mi*mf mod ni = 1;
则 a = (a1*c1+a2*c2+...+ak*ck) (mod n) (注:由此等式可求a%n, 当n很大时)
中国剩余定理关键是mf的求法,如果理解了扩展欧几里得 ax+by=d, 就可以想到:
mi*mf mod ni = 1 => mi*mf+ni*y=1;
代码如下:

const int MAXN = 100;    
int nn, a[MAXN], n[MAXN];    
int egcd(int a, int b, int &x, int &y) {    
    int d;    
    if (b == 0) {     
        x = 1; y = 0;    
        return a;    
    } else {    
        d = egcd(b, a%b, y, x);    
        y -= a/b*x;    
        return d;    
    }    
}    
int lmes() {    
    int i, tm=1, mf, y, ret=0, m;    
    for (i=0; i<nn; i++) tm *= n[i];    
        for (i=0; i<nn; i++) {    
            m = tm/n[i];    
            egcd(m, n[i], &mf, &y);    
            ret += (a[i]*m*(mf%n[i]))%tm;    
        }    
    return (ret+tm)%tm;    
}    
int main() {    
    a[0] = 4; a[1] = 5;     
    n[0] = 5; n[1] = 11;    
    nn = 2;    
    printf(“%d“, lmes());    
    return 0;    
}    

附录2:
求最小点基 <图论算法与程序设计> P49
求点连通度 <图论算法与程序设计> P102
附:北邮ACM50题
第一类 动态规划 (至少6题,2479 and 2593必做)
2479 and 2593 1015 1042 (也可贪心) 1141 1050 1080 1221 1260 2411 (稍难) 1276
第二类 搜索 (至少4题)
1011 1033 1129 2049 2056 2488 2492 (稍难,也可并查集)
第三类 贪心 (至少2题)
1065 2054 (难) 1521 2709
第四类 最短路 (至少3题)
1062 1125 1797 2253 2679 Bellman-Ford (难)
第五类 最小生成树 (至少2题, 而且 Prim 和 Kruskal 至少各用一次)
1251 1258 1789 2485
第六类 最大流 (至少2题)
1087 1459 1149 2516 (最小费用最大流) (难)
第七类 二分图 (至少3题)
1325 1469 2195 (KM 算法或最小费用最大流) (难) 2446 1422 and 2594
第八类 并查集 (至少2题)
1861 1182 (难) 1308 2524
第九类 快速查找 (B-Search, Hash and so on) (至少3题)
2503 2513 (+Euler回路的判定) 1035 1200 2002
第十类 数论 (至少2题)
1061 1142 2262 2407 1811(难) 2447 (难)
第十一类 线段树 (无最少题数要求)
2352 (可用简单方法) 2528
第十二类 计算几何 (至少2题,1113凸包算法必做)
1113 1292 2148 (难) 2653 1584
第十三类 高精度 (至少3题,1001必做)
1001 1047 1131 1503 1504 1060 and 1996 (多项式) SCU1002, 1003, 1004 (http:// acm.scu.edu.cn/soj)
第十四类 模拟 (至少5题)
1029 and 1013 1083 and 2028 2234 and 1067 1012 1026 1068 1120 2271 2632
第十五类 数学 (至少4题)
2249 1023 2506 1079 1019 and 1095 1905 and 1064 (二分)