$ ~. H2 T1 ^5 O( s7 ?& _) g: q竞赛中至少命题6题,至多命题10题,比赛时间为5个小时,参赛队员可以携带诸如书、手册、程序清单等参考资料,试题的解答提交裁判称为运行,每一次运行会被判为正确或者错误,判决结果会及时通知参赛队伍,正确解答中等数量及中等数量以上试题的队伍会根据解题数目进行排名,解题数在中等数量以下的队伍会得到确认但不会进行排名,在决定获奖和参加世界决赛的队伍时,如果多支队伍解题数量相同,则根据总用时加上惩罚时间进行排名,总用时和惩罚时间由每道解答正确的试题的用时加上惩罚时间而成。每道试题用时将从竞赛开始到试题解答被判定为正确为止,期间每一次错误的运行将被加罚20分钟时间,未正确解答的试题不记时,地区预赛可以使用的语言包括C/C++和Java,每支队伍使用一台计算机,所有队伍使用计算机的规格配置完全相同。(竞赛具体的软件环境可能根据赞助商的变化而变) 9 U' s: S; d9 Y* C$ ^7 j3 h. `3 l. ]8 R/ E
二、关于竞赛的题型分析% z/ i& z. ?* @9 G. x7 v
Hal Burch通过在1999年春季的分析得出了这样的结论,竞赛的程序设计一般只有16种类型,它们分别是:& ~4 [& \* w( l( Q+ R3 [' f% g
7 k* m. o0 O5 U3 }2 A8 oDynamic Programming (动态规划) # M5 c* I7 L4 e# F( O. J" b" A
Greedy (贪心算法) ! D/ Z1 U2 |8 I+ A/ ^% ~9 s; V" Q
Complete Search (穷举搜索) 3 J$ \* | v$ s* x' |Flood Fill (不知该如何翻译) % \. r6 z' X7 _4 X8 n; _$ M4 D
Shortest Path (最短路径) $ f2 Q* t4 N: D; d* k4 h6 a0 QRecursive Search Techniques (回溯搜索技术) ) k K8 v, n0 \Minimum Spanning Tree (最小生成树) ' ^! n& y4 r. P5 d
Knapsack (背包问题) - `1 s# b: |$ _3 w/ @! _$ t0 e: M
Computational Geometry (计算几何学) ' Y. ~0 ?0 b* b. vNetwork Flow (网络流) * \* L, g6 R5 z$ E
Eulerian Path (欧拉回路) + {4 J0 S$ L) s' K! X. T) R- pTwo-Dimensional Convex Hull (凸包问题) # B* K+ h! A, x9 {
BigNums (大数问题) 4 Z: H! X! K+ P8 L: j. C" }0 _& BHeuristic Search (启发式搜索) - E+ J; L% v) B/ w NApproximate Search (近似搜索) * K/ G1 |* k0 f7 K6 Q0 M4 mAd Hoc Problems (杂题)6 }% ^ r5 k' L' N; g, n4 z5 W
* \ F+ R6 i- p& r# c很少有人能真正掌握这其中绝大部分的方法,而对于一些包含了这些方法组合与循环的具有挑战性的综合问题,多数选手都无能为力,因为竞赛中的很多试题都需要选手当场作出分析,而不是套用固定的解题格式,这是竞赛的困难所在,也是它的魅力所在。% k6 C' @. r! O' o
. C x. R. T0 r M8 Q+ S三、竞赛准备) E8 Y' s' ^; r1 F% q1 C8 h% k
ACM竞赛不要求使用某一种特定的语言,所以各个队伍可以根据语言的特点和自己的特长选择,如果对语言的原理语法和特点均能做到成竹于胸、滥熟于心,在比赛的过程中就可以大大缩短调试的时间,从而获得优势。 & N9 H S* h; ]+ ]; I9 \" Y ; X, ?6 u& t1 y, _( a3 G然而编程之道就如武学之道,语言只是各门各派的武功招式,算法和数据结构则好比内功心法和武学原理。内力深厚,任何招式到了手上都能够化腐朽为神奇;掌握了武学原理,更能做到无招胜有招。选手在竞赛中最重要的素质,正体现于对算法和数据结构的掌握和理解上,通过对经典问题的分析,掌握各种算法的应用范围和数据结构的作用与具体实现,是每个选手在平时学习中的重点所在。8 i! a9 P- c: m+ E6 K6 y# i
1 L) M0 x* p0 D* l/ a四、竞赛策略 ; @# v- L+ u0 S) S; E临近比赛,在实力上已经难有质的提高,这时我们不妨将注意力转移到竞赛技巧方面,做不成武学道师也学个韦小宝。在ACM竞赛中,一般来说能成功解决半数或以上题目的队伍已经是相当优秀的,解决所有问题近乎天方夜潭,也就是说无论你的实力如何,都还有很大的改进余地,这其中比较重要的就是竞赛的策略。! v7 s1 u/ q* @( m! k# y
' T: x" V$ p# V) Y9 L2 ` I. m* H) c) N b
(1)分工的问题:9 ? J V: P8 V7 H9 w1 q
团队的配合十分重要,三个队员之间的合理分工可以大大改进解题的效率,根据队员的不同特点,不同的队伍可以采用不同的分配方式,其间一些细节的处理需要三个人有很好的默契。9 |+ U% y& _; ?- y5 b
' h$ R, e; G5 S(2)算法的选择: * ~0 `4 J) t& m- Y/ q' ~在所有可行的算法当中,我们选择的应该是最可行的方法,而不是最高明的方法,这是竞赛与解决问题的一个重要区别,按照熟悉的程度由高到低选择一个算法,通过计算算法的时间和空间复杂度(在必要的情况下)和特殊的测试数据找出一切使该算法不成立的理由,如果找不到就确定该算法并选用相应的数据结构。在确定思路的时候注意比较常见的思维方式分析,比如逆向的分析,对称的分析等等。 3 m3 b" {1 |% c1 C# M8 I1 V4 g& k# B; R* f+ e0 T2 q
(3)程序的编写:2 m5 i2 K& j) ~8 S8 ~
最好首先编写输入和输出的部分,然后逐步细化,一个部分一个部分地填充调试,其间通过适量的注释来刻画程序的逻辑结构和特殊的技巧。在完成全部代码后用一般的测试数据验证代码的正确性,然后处理特殊的情况和边界问题,试图尽可能地找出错误的情况并加以改正。关于程序的优化主要考虑的是最坏情况下所用的时间是否满足要求,优化的程度以题目要求为准,足够即可,尽量避免使用指针和动态分配,在空间允许的情况下一律采用静态分配。 , b+ D7 V, L2 M6 \ x7 Z& F. m: [# ^5 Y3 E3 [; [
(4)调试中的问题:. A: r+ ]3 H' \ T9 F
调试中会遇到的许多问题需要在事前有所准备并定出总体设计,当然具体的情况还要临场分析,考虑的方面包括程序中的BUG,算法的正确性和数据结构的合理性,什么时候该放弃这个问题,什么时候该返回到先前放弃的问题,是否需要做到或已经做到足够的优化等等。所有关于调试的输入输出都不要删除,将它们注释起来即可。8 t7 o" O! B. u9 e5 x9 n
5 [" ~9 _5 I9 F, q' r/ e
(5)竞赛中的杂题处理 * g5 O0 @& I* D1 a. g6 r# t. j在竞赛中有时会出现一些新颖的题型,解决它们的算法很难归到经典的算法中去,每个这类的题都有自己鲜明的特点,对于它们根本没有一般的解法。对于这样的挑战,一个新颖的数据结构或一套特殊的循环或判断常常是必须的。解决这种问题的关键在于仔细地阅读题目的叙述,灵感经常来自于将叙述的逻辑条理整理得十分清楚之后,同样,对这类题的优化也是需要的,至少需要避免过多的循环嵌套。8 F9 V' R, S, z8 q
7 j9 n7 j1 W$ z/ L( h c
五、编程与竞赛 Q3 h+ B" m# Q) I: F) {; y
学习编程并不是为了参加竞赛,竞赛对于多数选手的意义还是在于参与,以及在备战过程中对自己的锻炼和提高。在这一点上,ACM竞赛和其它一系列竞赛是一样的,只是它的影响力和规模大些罢了,所以笔者希望对编程有兴趣的同学都能够关注竞赛,即使不参加,通过了解竞赛中涉及的编程知识达到课内很难达到的高度,这对每个人都是有益无害的。 : v V" |+ y. I" z# A3 f* B } % Y7 `. M) W8 n0 w `9 {1 i ; B: l. u% m" n- l7 G8 O$ k8 T5 I. i4 m8 A4 l; e. N/ p$ G# g8 Z, y
一、语言是最重要的基本功: q# d4 W' B3 n; N