一、ACM竞赛介绍及规则 % j4 b( `+ Y7 b( j, Q9 ]ACM/ICPC(国际大学生程序设计竞赛)是由ACM(Association for Computing Machinery,美国计算机协会)组织的年度性竞赛,始于1970年,是全球大学生计算机程序能力竞赛活动中最有影响的一项赛事。ACM/ICPC采用赛区选拔的方式产生参加世界决赛学校的资格, 2001年,来自全球超过25个地区1141所大学的2362支队伍参加了第26届ACM/ICPC的赛区竞赛。在2002年3月,来自世界各地的约60支队伍,200多名选手参加了夏威夷总决赛的角逐。可以说,ACM国际大学生程序设计竞赛是参赛选手展示计算机才华的广阔舞台,是著名大学计算机教育成果的直接体现,是信息企业与世界顶尖计算机人才对话的最好机会。在过去十几年中,世界著名信息企业APPLE、AT&T、MICROSOFT和IBM分别担任了竞赛的赞助商。中国大陆高校从1996年开始参加ACM/ICPC亚洲预赛,前五届ACM/ICPC亚洲区选拔赛在上海设有赛区,由上海大学主办。2002年,第六届ACM/ICPC亚洲预赛将该在北京设赛区,由清华大学主办。本次竞赛将于2002年10月在清华园拉开帷幕,预计将有超过60所国内外著名大学的上百支队伍参加本次竞赛(这也是北京工业大学首次参加此项赛事)。) ^! l+ Z Q! ]& c; R1 {2 `6 K
) y) f l* V: L9 j6 Y) fACM竞赛规定,教练是参赛队伍所代表学校的正式教师,每支队伍最多由三名参赛队员组成,每支队伍中至少有两名参赛队员必须是未取得学士学位或同等学历的学生,取得学士学位超过两年,或进行研究生学习超过两年的学生不符合参赛队员的资格,任何参加过两次决赛的学生不得参加地区预赛或者世界决赛。& l8 e J$ h- ~2 {) e _/ ~, E
; p ^( ?8 m5 O2 R竞赛中至少命题6题,至多命题10题,比赛时间为5个小时,参赛队员可以携带诸如书、手册、程序清单等参考资料,试题的解答提交裁判称为运行,每一次运行会被判为正确或者错误,判决结果会及时通知参赛队伍,正确解答中等数量及中等数量以上试题的队伍会根据解题数目进行排名,解题数在中等数量以下的队伍会得到确认但不会进行排名,在决定获奖和参加世界决赛的队伍时,如果多支队伍解题数量相同,则根据总用时加上惩罚时间进行排名,总用时和惩罚时间由每道解答正确的试题的用时加上惩罚时间而成。每道试题用时将从竞赛开始到试题解答被判定为正确为止,期间每一次错误的运行将被加罚20分钟时间,未正确解答的试题不记时,地区预赛可以使用的语言包括C/C++和Java,每支队伍使用一台计算机,所有队伍使用计算机的规格配置完全相同。(竞赛具体的软件环境可能根据赞助商的变化而变)/ X' w2 `. F* b* u, u
9 v6 e5 q; d' Y1 J w二、关于竞赛的题型分析+ _$ e- s2 ~! C. t
Hal Burch通过在1999年春季的分析得出了这样的结论,竞赛的程序设计一般只有16种类型,它们分别是:0 x' m$ y) M% O% k9 F' b& g
* O @% ]9 A' `' i1 ?Dynamic Programming (动态规划) # q, @# G8 _ i, G9 e1 p0 y
Greedy (贪心算法) 8 H( e% J% A! u& u( P _) dComplete Search (穷举搜索) ' U1 y: O, r/ a; UFlood Fill (不知该如何翻译) 2 U: } v$ w; t' g4 g1 N4 K0 G2 k
Shortest Path (最短路径) : J2 x" S- Q1 j. s8 e* bRecursive Search Techniques (回溯搜索技术) " N# y {, [7 ?% K) f( W
Minimum Spanning Tree (最小生成树) " w, u2 w. ^4 t3 ?8 Y
Knapsack (背包问题) / ]. r1 I, ^$ \' o2 ]# OComputational Geometry (计算几何学) 6 f' e: G2 P' H. i0 B3 M1 G+ NNetwork Flow (网络流) L- v! V8 T2 h! E' b- l) f4 }2 I
Eulerian Path (欧拉回路) 5 o( I7 Y2 ?8 G( t8 n! TTwo-Dimensional Convex Hull (凸包问题) 6 g3 S" x& t9 y% mBigNums (大数问题) : c2 {6 C+ s/ q6 W! {( l. l
Heuristic Search (启发式搜索) 8 Q% s5 _9 I8 }* P7 O1 cApproximate Search (近似搜索) ( f& e* A. v! ~4 A
Ad Hoc Problems (杂题) 8 B/ n& o+ s0 V4 h4 z8 a 1 ?- P% Z9 s' y5 G/ X/ r很少有人能真正掌握这其中绝大部分的方法,而对于一些包含了这些方法组合与循环的具有挑战性的综合问题,多数选手都无能为力,因为竞赛中的很多试题都需要选手当场作出分析,而不是套用固定的解题格式,这是竞赛的困难所在,也是它的魅力所在。 , B& r& I/ `% ?9 D" O4 @: |& [' e7 F5 ?, ^# m* C
三、竞赛准备+ G7 Y' L4 n# N+ u2 R' Z! S
ACM竞赛不要求使用某一种特定的语言,所以各个队伍可以根据语言的特点和自己的特长选择,如果对语言的原理语法和特点均能做到成竹于胸、滥熟于心,在比赛的过程中就可以大大缩短调试的时间,从而获得优势。9 n/ i( M+ R5 E, c( D
5 E4 ?1 o, [# S
然而编程之道就如武学之道,语言只是各门各派的武功招式,算法和数据结构则好比内功心法和武学原理。内力深厚,任何招式到了手上都能够化腐朽为神奇;掌握了武学原理,更能做到无招胜有招。选手在竞赛中最重要的素质,正体现于对算法和数据结构的掌握和理解上,通过对经典问题的分析,掌握各种算法的应用范围和数据结构的作用与具体实现,是每个选手在平时学习中的重点所在。# S9 G( I; z& i2 ?) Z' _
$ I% ?7 ^" v3 B$ J6 D四、竞赛策略* J/ F" L- }9 ?+ V6 O& M
临近比赛,在实力上已经难有质的提高,这时我们不妨将注意力转移到竞赛技巧方面,做不成武学道师也学个韦小宝。在ACM竞赛中,一般来说能成功解决半数或以上题目的队伍已经是相当优秀的,解决所有问题近乎天方夜潭,也就是说无论你的实力如何,都还有很大的改进余地,这其中比较重要的就是竞赛的策略。2 p2 s5 N- G& Y, ?1 r2 D
3 @# x# r ]* F9 }(1)分工的问题: 5 L& j" p' C+ v( N1 O9 f团队的配合十分重要,三个队员之间的合理分工可以大大改进解题的效率,根据队员的不同特点,不同的队伍可以采用不同的分配方式,其间一些细节的处理需要三个人有很好的默契。8 h; S# }8 N1 ^0 ]7 s2 Q3 W# x$ M" [# A
. _+ H' P1 C; A+ V五、编程与竞赛 r& h& F: {& I Z3 Y, u
学习编程并不是为了参加竞赛,竞赛对于多数选手的意义还是在于参与,以及在备战过程中对自己的锻炼和提高。在这一点上,ACM竞赛和其它一系列竞赛是一样的,只是它的影响力和规模大些罢了,所以笔者希望对编程有兴趣的同学都能够关注竞赛,即使不参加,通过了解竞赛中涉及的编程知识达到课内很难达到的高度,这对每个人都是有益无害的。9 t+ \; l# W! C! N- y F
/ x( b. h3 u+ N+ R7 z W8 W& `' w! C, p% T$ A8 m$ Z( R: {/ ~( l- b. h" U
一、语言是最重要的基本功 4 v& f ^" a, k | t4 u, A0 @' A
无论侧重于什么方面,只要是通过计算机程序去最终实现的竞赛,语言都是大家要过的第一道关。亚洲赛区的比赛支持的语言包括C/C++与JAVA。笔者首先说说JAVA,众所周知,作为面向对象的王牌语言,JAVA在大型工程的组织与安全性方面有着自己独特的优势,但是对于信息学比赛的具体场合,JAVA则显得不那么合适,它对于输入输出流的操作相比于C++要繁杂很多,更为重要的是JAVA程序的运行速度要比C++慢10倍以上,而竞赛中对于JAVA程序的运行时限却往往得不到同等比例的放宽,这无疑对算法设计提出了更高的要求,是相当不利的。其实,笔者并不主张大家在这种场合过多地运用面向对象的程序设计思维,因为对于小程序来说这不旦需要花费更多的时间去编写代码,也会降低程序的执行效率。 3 H& y# r a; v' G 7 x6 j4 E t1 |2 d! q' H+ C$ P接着说C和C++。许多现在参加讲座的同学还在上大一,C的基础知识刚刚学完,还没有接触过C++,其实在赛场上使用纯C的选手还是大有人在的,它们主要是看重了纯C在效率上的优势,所以这部分同学如果时间有限,并不需要急着去学习新的语言,只要提高了自己在算法设计上的造诣,纯C一样能发挥巨大的威力。: `+ j, u- A3 V* U( y
0 n" p, h# f1 j$ M
而C++相对于C,在输入输出流上的封装大大方便了我们的操作,同时降低了出错的可能性,并且能够很好地实现标准流与文件流的切换,方便了调试的工作。如果有些同学比较在意这点,可以尝试C和C++的混编,毕竟仅仅学习C++的流操作还是不花什么时间的。 [* [0 c+ i2 A$ I+ G3 N5 G o" c; k- n3 s
C++的另一个支持来源于标准模版库(STL),库中提供的对于基本数据结构的统一接口操作和基本算法的实现可以缩减我们编写代码的长度,这可以节省一些时间。但是,与此相对的,使用STL要在效率上做出一些牺牲,对于输入规模很大的题目,有时候必须放弃STL,这意味着我们不能存在“有了STL就可以不去管基本算法的实现”的想法;另外,熟练和恰当地使用STL必须经过一定时间的积累,准确地了解各种操作的时间复杂度,切忌对STL中不熟悉的部分滥用,因为这其中蕴涵着许多初学者不易发现的陷阱。9 C7 e) p) Q5 V/ m1 n) k
6 ]% [& ?8 D0 E; }. j$ t; w通过以上的分析,我们可以看出仅就信息学竞赛而言,对语言的掌握并不要求十分全面,但是对于经常用到的部分,必须十分熟练,不允许有半点不清楚的地方,下面我举个真实的例子来说明这个道理——即使是一点很细微的语言障碍,都有可能酿成错误: ! V9 d; w3 n: O+ C3 [+ y3 B; l$ K2 |3 i; @- P9 {, L. D
在去年清华的赛区上,有一个队在做F题的时候使用了cout和printf的混合输出,由于一个带缓冲一个不带,所以输出一长就混乱了。只是因为当时 judge team中负责F题的人眼睛尖,看出答案没错只是顺序不对(答案有一页多,是所有题目中最长的一个输出),又看了看程序发现只是输出问题就给了个 Presentation error(格式错)。如果审题的人不是这样而是直接给一个 Wrong Answer,相信这个队是很难查到自己错在什么地方的。 $ [- G2 c" g2 T9 S" o* f1 i" u# D, R$ H# u7 j( r
现在我们转入第二个方面的讨论,基础学科知识的积累。 ' Z$ y' n" ~9 l4 H: a8 v# `$ a: y! y; W2 m
二、以数学为主的基础知识十分重要' u, p. I( m) z& |* I+ X
0 U8 d3 j0 [4 J1 @$ {: n4 t虽然被定性为程序设计竞赛,但是参赛选手所遇到的问题更多的是没有解决问题的思路,而不是有了思路却死活不能实现,这就是平时积累的基础知识不够。今年 World Final的总冠军是波兰华沙大学,其成员出自于数学系而非计算机系,这就是一个鲜活的例子。竞赛中对于基础学科的涉及主要集中于数学,此外对于物理、电路等等也可能有一定应用,但是不多。因此,大一的同学也不必为自己还没学数据结构而感到不知从何入手提高,把数学捡起来吧!下面我来谈谈在竞赛中应用的数学的主要分支。$ _6 K3 }$ j7 p
! G3 B! f& C6 }1、离散数学——作为计算机学科的基础,离散数学是竞赛中涉及最多的数学分支,其重中之重又在于图论和组合数学,尤其是图论。( u( i+ ^" ?$ e( s& S0 X( N
% Y8 Y; U* V2 a' h1 k* w
图论之所以运用最多是因为它的变化最多,而且可以轻易地结合基本数据结构和许多算法的基本思想,较多用到的知识包括连通性判断、DFS和BFS,关节点和关键路径、欧拉回路、最小生成树、最短路径、二部图匹配和网络流等等。虽然这部分的比重很大,但是往往也是竞赛中的难题所在,如果有初学者对于这部分的某些具体内容暂时感到力不从心,也不必着急,可以慢慢积累。 / U/ \0 \* B4 C O0 d4 F% D/ ^. v j+ ~; G% S1 m
竞赛中设计的组合计数问题大都需要用组合数学来解决,组合数学中的知识相比于图论要简单一些,很多知识对于小学上过奥校的同学来说已经十分熟悉,但是也有一些部分需要先对代数结构中的群论有初步了解才能进行学习。组合数学在竞赛中很少以难题的形式出现,但是如果积累不够,任何一道这方面的题目却都有可能成为难题。+ |9 }$ b$ A3 o# m7 t2 H
' v7 {5 l% W5 c* q& v: n( W
2、数论——以素数判断和同余为模型构造出来的题目往往需要较多的数论知识来解决,这部分在竞赛中的比重并不大,但只要来上一道,也足以使知识不足的人冥思苦想上一阵时间。素数判断和同余最常见的是在以密码学为背景的题目中出现,在运用密码学常识确定大概的过程之后,核心算法往往要涉及数论的内容。 + s* v6 p8 [( e+ M" G) n K, ]( I m# N# U
3、计算几何——计算几何相比于其它部分来说是比较独立的,就是说它和其它的知识点很少有过多的结合,较常用到的部分包括——线段相交的判断、多边形面积的计算、内点外点的判断、凸包等等。计算几何的题目难度不会很大,但也永远不会成为最弱的题。 % z4 _& ^0 E* N* o4 k5 m @/ Z$ e/ l; ]% ]- [4、线性代数——对线性代数的应用都是围绕矩阵展开的,一些表面上是模拟的题目往往可以借助于矩阵来找到更好的算法。 . L8 o+ f5 ~: c8 E0 ]' j e 1 r; v: R, S. H M8 ]- }! T5、概率论——竞赛是以黑箱来判卷的,这就是说你几乎不能动使用概率算法的念头,但这也并不是说概率就没有用。关于这一点,只有通过一定的练习才能体会。9 Z0 I' K% N' ~6 r( t7 X" K3 W; @
+ f: u# A3 j5 m8 d7 {6 h( [6 @; N0 g
6、初等数学与解析几何——这主要就是中学的知识了,用的不多,但是至少比高等数学多,我觉得熟悉一下数学手册上的相关内容,至少要知道在哪儿能查到,还是必要的。! B3 y# u; j8 S# L$ x