ACM学习经验

来源:互联网 发布:软件监理公司 编辑:程序博客网 时间:2024/06/03 06:30
首先可以说,在我认识的顶尖的 ACMer 中,很多人走的都不是在 OJ 盲目刷题的路。(当然也有特例,前提是他们的某方面基础或智商本身已经达到很高的水平。)不盲目刷题,我想原因也很简单,OJ 题目质量良莠不齐。对于大部分比赛套题来说,总会有防止人吃蛋的水题,也有故意刁难型的题目,有些赛区还流行论文题(结论题)、模板题,这些题目都不具备多少训练价值。而且,如果陷入了刷题量的虚荣漩涡,那会浪费很多时间。

有效地刷题只有两种情况:
  1. 刷套题。找比赛的感觉,给自己定位;
  2. 刷知识点专题。巩固基础。

除了刷题,更重要的一件事是做比赛。一般来说,建议常去 TopCoder Codeforces 比赛。这些地方题目质量有保障,大家的代码是公开的。同时很关键的是,这样的平台可以让你对题目的难度、比赛的进度、国内外顶级选手的实力做到心中有数,培养在大型比赛中所需要的大局观和节奏感。

另外,你可以尝试忘掉拿奖的事情。只要你真的有兴趣,拿奖是小 case
首先,想象摸象样的参加regional,不被切的太难看,要训练基本的能力,该想到的都想到,大家都会的算法你也要会
然后,要避免切水题,切一些稍稍高过自己水平的较难题,自虐提高难度
TC div2 500-1000, div1都是锻炼思维的神器
spoj的数据结构题要切一些
还有sgu,不过切不动...
ACM本身没有止境,如果所有东西都会,感到胸有成竹,建议看看算法书...一定会有新发现的
1. 理论部分
初学阶段要做的就是熟悉语言基础;熟悉基本数据结构和常见简单算法。
这些内容,书本里都有。推荐的书籍,《算法导论》。至于语言入门书太多了,不列举。
进阶阶段,看一下圈内的论文,学习进阶的算法和数据结构,比如变种的平衡树SBT;比如线性的素数筛法,中国剩余定理;比如dinic,预留推进,最高顶标;亦或者是快速的半平面交,凸包的交,高维凸包;又比如龙贝格积分,拉格朗日插值。
这里面有个重要的分类,就是动态规划。其实动态规划在学术界,我就用呵呵来形容好了。因为你根本就遇不到OI/ACM中那么复杂绕人的问题和模型,即使遇到了,直接建模,剩下的交给cplex就好。但是,在ACM界你会遇到很多很多的DP问题,变种,卡空间、卡时间,各种卡。所以得多看论文,培养解题的感觉是很重要的。
前一部分还是可以找到一些好看的书籍的,比如网络流,数论(初等数论、计算数论),数值分析,计算几何等。至于DP则没有啥好书了,作为一个刚上路的人,你会觉得理论和现实,差距真的好远好远。(但回过头来会发现其实理论真的描述了一切)
高级阶段,如果说初学阶段要做的是打基础,进阶阶段是加深深度,那么高级阶段就是加大广度。你需要涉猎许多理论,系统性的学习。比如你只知道dinic,只知道dijkstra,只知道bellman-ford是不行的,你需要知道整个图论它大概讲的是啥,你需要知道还有什么你是不懂的,不会的;再比如你只知道孙子定理,只知道丢番图方程是不行的,你需要系统地学习数论知识,你要深刻理解欧拉函数,要深刻理解莫比乌斯函数,要深刻理解扩展欧几里德,要深刻理解原根,等等等等。这样你才能知道原来扩展欧几里德可以轻松解出线性丢番图方程,你才能知道原来解二次丢番图方程要先解一下佩尔方程,你才能知道解高次同余方程就是质因数分解+扩展欧几里德+中国剩余定理。
在你涉猎了足够多的知识之后,再选择性的深入学习。为什么说是选择性的深入学习呢?因为一个人的精力始终有限,方方面面不能都照顾到,剩下的就要交给队友了,不然ACM为啥是个三人的比赛呢?
2. 实践部分
其实实践部分才是重中之重。
首先要知道ACM的代码是个什么样的水平。
1. 代码不多,大多在100行左右,多的在300行左右。当然,这些都是普遍的,也不排除有很长很长的代码。或者换种说法,大多数代码在1KBit左右,长的代码在3K,打表的代码不算。

2. 编程风格极“差”。这其中的代表有:
(1)几乎所有变量都是全局变量,因为平时练习中有内存限制,而静态变量区的大小足以应付。并且我们都知道,静态区的速度是要优于堆区的速度的,所以一般是不用new或者malloc的。
(2)代码怎么简单怎么写,以效率第一,牺牲部分代码可读性,牺牲安全性。
举个例子,比如用C++的选手,在没有特殊情况下,一般使用scanf而不用cin,这是因为前者效率比后者高许多,但scanf是有很多安全漏洞的,但是我们不管,因为我们正确的使用是不会导致问题的。
再举个例子,比如你用scanf读数据读到文件尾(EOF),一般的想法是用EOF != scanf(...)作为循环判断条件,而ACMer可能会写成~scanf(...)。总之,代码简写,效率第一。

3. ACM里的代码大多数是结构化编程,面向对象的绝对不用,基于对象的可以用一点。这是由于代码长度和效率优先的思想综合导致的。

好了,接下来是实践的正文。
ACM最重要的是什么,是代码控制力。要做到写代码跟你讲话一样,不说错字(编译错误),不说错话(运行错误),表意正确(代码逻辑正确)。楼上说的做TC、CF的比赛当然是好的,但是这些并不适合初学者。




初期:
.基本算法:
    (1)枚举. (poj1753,poj2965) (2)贪心(poj1328,poj2109,poj2586)
    (3)递归和分治法. (4)递推.
    (5)构造法.(poj3295) (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)
.图算法:
    (1)图的深度优先遍历和广度优先遍历.
    (2)最短路径算法(dijkstra,bellman-ford,floyd,heap+dijkstra)
        (poj1860,poj3259,poj1062,poj2253,poj1125,poj2240)
    (3)最小生成树算法(prim,kruskal)
        (poj1789,poj2485,poj1258,poj3026)
    (4)拓扑排序 (poj1094)
    (5)二分图的最大匹配 (匈牙利算法) (poj3041,poj3020)
    (6)最大流的增广路算法(KM算法). (poj1459,poj3436)
.数据结构.
    (1)串 (poj1035,poj3080,poj1936)
    (2)排序(快排、归并排(与逆序数有关)、堆排) (poj2388,poj2299)
    (3)简单并查集的应用.
    (4)哈希表和二分查找等高效查找法(数的Hash,串的Hash) 
        (poj3349,poj3274,POJ2151,poj1840,poj2002,poj2503)
    (5)哈夫曼树(poj3253)
    (6)
    (7)trie树(静态建树、动态建树) (poj2513)
.简单搜索
    (1)深度优先搜索 (poj2488,poj3083,poj3009,poj1321,poj2251)
    (2)广度优先搜索(poj3278,poj1426,poj3126,poj3087.poj3414)
    (3)简单搜索技巧和剪枝(poj2531,poj1416,poj2676,1129)
.动态规划
    (1)背包问题. (poj1837,poj1276)
    (2)型如下表的简单DP(可参考lrj的书 page149):
      1.E[j]=opt{D+w(i,j)} (poj3267,poj1836,poj1260,poj2533)
      2.E[i,j]=opt{D}


初期:
.基本算法:
    (1)枚举. (poj1753,poj2965) (2)贪心(poj1328,poj2109,poj2586)
    (3)递归和分治法. (4)递推.
    (5)构造法.(poj3295) (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)
.图算法:
    (1)图的深度优先遍历和广度优先遍历.
    (2)最短路径算法(dijkstra,bellman-ford,floyd,heap+dijkstra)
        (poj1860,poj3259,poj1062,poj2253,poj1125,poj2240)
    (3)最小生成树算法(prim,kruskal)
        (poj1789,poj2485,poj1258,poj3026)
    (4)拓扑排序 (poj1094)
    (5)二分图的最大匹配 (匈牙利算法) (poj3041,poj3020)
    (6)最大流的增广路算法(KM算法). (poj1459,poj3436)
.数据结构.
    (1)串 (poj1035,poj3080,poj1936)
    (2)排序(快排、归并排(与逆序数有关)、堆排) (poj2388,poj2299)
    (3)简单并查集的应用.
    (4)哈希表和二分查找等高效查找法(数的Hash,串的Hash) 
        (poj3349,poj3274,POJ2151,poj1840,poj2002,poj2503)
    (5)哈夫曼树(poj3253)
    (6)
    (7)trie树(静态建树、动态建树) (poj2513)
.简单搜索
    (1)深度优先搜索 (poj2488,poj3083,poj3009,poj1321,poj2251)
    (2)广度优先搜索(poj3278,poj1426,poj3126,poj3087.poj3414)
    (3)简单搜索技巧和剪枝(poj2531,poj1416,poj2676,1129)
.动态规划
    (1)背包问题. (poj1837,poj1276)
    (2)型如下表的简单DP(可参考lrj的书 page149):
      1.E[j]=opt{D+w(i,j)} (poj3267,poj1836,poj1260,poj2533)
      2.E[i,j]=opt{D




第一阶段:练经典常用算法,下面的每个算法要打得非常的熟练,同时自己精简代码,
因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打
出来.(这个有点夸张吧?
1.最短路(Floyd、Dijstra,BellmanFord)
2.最小生成树(先写个prim,kruscal要用并查集,不好写)
3.大数(高精度)加减乘除
4.二分查找. (代码可在五行以内)
5.叉乘、判线段相交、然后写个凸包.
6.BFS、DFS,同时熟练hash表(要熟,要灵活,代码要简)
7.数学上的有:辗转相除(两行内),线段交点、多角形面积公式.
8. 调用系统的qsort, 技巧很多,慢慢掌握.
9. 任意进制间的转换



第二阶段:练习复杂一点,但也较常用的算法。
如:
1. 二分图匹配(匈牙利),最小路径覆盖
2. 网络流,最小费用流。
3. 线段树.
4. 并查集。
5. 熟悉动态规划的各个典型:LCS、最长递增子串、三角剖分、记忆化dp
6.博弈类算法。博弈树,二进制法等。
7.最大团,最大独立集。
8.判断点在多边形内。
9. 差分约束系统.
10. 双向广度搜索、A*算法,最小耗散优先.



初期:
.基本算法:
    (1)枚举. (poj1753,poj2965) (2)贪心(poj1328,poj2109,poj2586)
    (3)递归和分治法. (4)递推.
    (5)构造法.(poj3295) (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)
.图算法:
    (1)图的深度优先遍历和广度优先遍历.
    (2)最短路径算法(dijkstra,bellman-ford,floyd,heap+dijkstra)
        (poj1860,poj3259,poj1062,poj2253,poj1125,poj2240)
    (3)最小生成树算法(prim,kruskal)
        (poj1789,poj2485,poj1258,poj3026)
    (4)拓扑排序 (poj1094)
    (5)二分图的最大匹配 (匈牙利算法) (poj3041,poj3020)
    (6)最大流的增广路算法(KM算法). (poj1459,poj3436)
.数据结构.
    (1)串 (poj1035,poj3080,poj1936)
    (2)排序(快排、归并排(与逆序数有关)、堆排) (poj2388,poj2299)
    (3)简单并查集的应用.
    (4)哈希表和二分查找等高效查找法(数的Hash,串的Hash) 
        (poj3349,poj3274,POJ2151,poj1840,poj2002,poj2503)
    (5)哈夫曼树(poj3253)
    (6)
    (7)trie树(静态建树、动态建树) (poj2513)
.简单搜索
    (1)深度优先搜索 (poj2488,poj3083,poj3009,poj1321,poj2251)
    (2)广度优先搜索(poj3278,poj1426,poj3126,poj3087.poj3414)
    (3)简单搜索技巧和剪枝(poj2531,poj1416,poj2676,1129)
.动态规划
    (1)背包问题. (poj1837,poj1276)
    (2)型如下表的简单DP(可参考lrj的书 page149):
      1.E[j]=opt{D+w(i,j)} (poj3267,poj1836,poj1260,poj2533)
      2.E[i,j]=opt{D


第一阶段:练经典常用算法,下面的每个算法要打得非常的熟练,同时自己精简代码,
因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打
出来.(这个有点夸张吧?
1.最短路(Floyd、Dijstra,BellmanFord)
2.最小生成树(先写个prim,kruscal要用并查集,不好写)
3.大数(高精度)加减乘除
4.二分查找. (代码可在五行以内)
5.叉乘、判线段相交、然后写个凸包.
6.BFS、DFS,同时熟练hash表(要熟,要灵活,代码要简)
7.数学上的有:辗转相除(两行内),线段交点、多角形面积公式.
8. 调用系统的qsort, 技巧很多,慢慢掌握.
9. 任意进制间的转换



第二阶段:练习复杂一点,但也较常用的算法。
如:
1. 二分图匹配(匈牙利),最小路径覆盖
2. 网络流,最小费用流。
3. 线段树.
4. 并查集。
5. 熟悉动态规划的各个典型:LCS、最长递增子串、三角剖分、记忆化dp
6.博弈类算法。博弈树,二进制法等。
7.最大团,最大独立集。
8.判断点在多边形内。
9. 差分约束系统.
10. 双向广度搜索、A*算法,最小耗散优先.





相关的知识
图论
  路径问题
        0/1边权最短路径
        BFS
        非负边权最短路径(Dijkstra)
            可以用Dijkstra解决问题的特征
        负边权最短路径
        Bellman-Ford
            Bellman-Ford的Yen-氏优化
            差分约束系统
        Floyd
            广义路径问题
            传递闭包
            极小极大距离 / 极大极小距离
        Euler Path / Tour
            圈套圈算法
            混合图的 Euler Path / Tour
        Hamilton Path / Tour
            特殊图的Hamilton Path / Tour 构造

 生成树问题
        最小生成树
        第k小生成树
        最优比率生成树
        0/1分数规划
        度限制生成树

 连通性问题
        强大的DFS算法
        无向图连通性
            割点
            割边
            二连通分支
            有向图连通性
            强连通分支
            2-SAT
            最小点基

 有向无环图
        拓扑排序
            有向无环图与动态规划的关系

    二分图匹配问题
        一般图问题与二分图问题的转换思路
        最大匹配
            有向图的最小路径覆盖
            0 / 1矩阵的最小覆盖
        完备匹配
        最优匹配
        稳定婚姻

    网络流问题
        网络流模型的简单特征和与线性规划的关系
        最大流最小割定理
        最大流问题
            有上下界的最大流问题
            循环流
            最小费用最大流 / 最大费用最大流

    弦图的性质和判定

组合数学

    解决组合数学问题时常用的思想
        逼近
        递推 / 动态规划
    概率问题
        Polya定理


计算几何 / 解析几何

    计算几何的核心:叉积 / 面积
    解析几何的主力:复数

    基本形
        点
        直线,线段
        多边形

    凸多边形 / 凸包
        凸包算法的引进,卷包裹法

    Graham扫描法
        水平序的引进,共线凸包的补丁

    完美凸包算法

    相关判定
        两直线相交
        两线段相交
        点在任意多边形内的判定
        点在凸多边形内的判定

    经典问题
        最小外接圆
            近似O(n)的最小外接圆算法
        点集直径
            旋转卡壳,对踵点
        多边形的三角剖分


数学 / 数论

  最大公约数
        Euclid算法
            扩展的Euclid算法
                同余方程 / 二元一次不定方程
                同余方程组

    线性方程组
        高斯消元法
        解mod 2域上的线性方程组
        整系数方程组的精确解法

    矩阵
        行列式的计算
            利用矩阵乘法快速计算递推关系

    分数
        分数树
        连分数逼近

    数论计算
        求N的约数个数
        求phi(N)
        求约数和
        快速数论变换
        ……

    素数问题
        概率判素算法
        概率因子分解


数据结构

    组织结构
        二叉堆
        左偏树
        二项树
        胜者树
        跳跃表
        样式图标
        斜堆
        reap

    统计结构
        树状数组
        虚二叉树
        线段树
            矩形面积并
            圆形面积并

    关系结构
        Hash表
        并查集
            路径压缩思想的应用

    STL中的数据结构
        vector
        deque
        set / map


动态规划 / 记忆化搜索

  动态规划和记忆化搜索在思考方式上的区别

    最长子序列系列问题
        最长不下降子序列
        最长公共子序列
        最长公共不下降子序列

    一类NP问题的动态规划解法

    树型动态规划

    背包问题

    动态规划的优化
        四边形不等式
        函数的凸凹性
        状态设计
        规划方向


线性规划

常用思想

    二分 最小表示法


    KMP Trie结构
    后缀树/后缀数组 LCA/RMQ
    有限状态自动机理论

排序
    选择/冒泡 
    快速排序 
    堆排序 
    归并排序
    基数排序 
    拓扑排序 
    排序网络



初期:
.基本算法:
    (1)枚举. (poj1753,poj2965) (2)贪心(poj1328,poj2109,poj2586)
    (3)递归和分治法. (4)递推.
    (5)构造法.(poj3295) (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)
.图算法:
    (1)图的深度优先遍历和广度优先遍历.
    (2)最短路径算法(dijkstra,bellman-ford,floyd,heap+dijkstra)
        (poj1860,poj3259,poj1062,poj2253,poj1125,poj2240)
    (3)最小生成树算法(prim,kruskal)
        (poj1789,poj2485,poj1258,poj3026)
    (4)拓扑排序 (poj1094)
    (5)二分图的最大匹配 (匈牙利算法) (poj3041,poj3020)
    (6)最大流的增广路算法(KM算法). (poj1459,poj3436)
.数据结构.
    (1)串 (poj1035,poj3080,poj1936)
    (2)排序(快排、归并排(与逆序数有关)、堆排) (poj2388,poj2299)
    (3)简单并查集的应用.
    (4)哈希表和二分查找等高效查找法(数的Hash,串的Hash) 
        (poj3349,poj3274,POJ2151,poj1840,poj2002,poj2503)
    (5)哈夫曼树(poj3253)
    (6)
    (7)trie树(静态建树、动态建树) (poj2513)
.简单搜索
    (1)深度优先搜索 (poj2488,poj3083,poj3009,poj1321,poj2251)
    (2)广度优先搜索(poj3278,poj1426,poj3126,poj3087.poj3414)
    (3)简单搜索技巧和剪枝(poj2531,poj1416,poj2676,1129)
.动态规划
    (1)背包问题. (poj1837,poj1276)
    (2)型如下表的简单DP(可参考lrj的书 page149):
      1.E[j]=opt{D+w(i,j)} (poj3267,poj1836,poj1260,poj2533)
      2.E[i,j]=opt{D

第一阶段:练经典常用算法,下面的每个算法要打得非常的熟练,同时自己精简代码,
因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打
出来.(这个有点夸张吧?
1.最短路(Floyd、Dijstra,BellmanFord)
2.最小生成树(先写个prim,kruscal要用并查集,不好写)
3.大数(高精度)加减乘除
4.二分查找. (代码可在五行以内)
5.叉乘、判线段相交、然后写个凸包.
6.BFS、DFS,同时熟练hash表(要熟,要灵活,代码要简)
7.数学上的有:辗转相除(两行内),线段交点、多角形面积公式.
8. 调用系统的qsort, 技巧很多,慢慢掌握.
9. 任意进制间的转换



第二阶段:练习复杂一点,但也较常用的算法。
如:
1. 二分图匹配(匈牙利),最小路径覆盖
2. 网络流,最小费用流。
3. 线段树.
4. 并查集。
5. 熟悉动态规划的各个典型:LCS、最长递增子串、三角剖分、记忆化dp
6.博弈类算法。博弈树,二进制法等。
7.最大团,最大独立集。
8.判断点在多边形内。
9. 差分约束系统.
10. 双向广度搜索、A*算法,最小耗散优先.


1 0