基本信息
作者: (日)秋叶拓哉 岩田阳一 北川宜稔
译者: 巫泽俊 庄俊元 李津羽
丛书名: 图灵程序设计丛书
出版社:人民邮电出版社
ISBN:9787115320100
上架时间:2013-6-14
出版日期:2013 年7月
开本:16开
页码:414
版次:2-1
所属分类:计算机 > 软件与程序设计 > 综合 > 综合
编辑推荐
世界顶级程序设计高手的经验总结
【ACM-ICPC全球总冠军】巫泽俊主译
日本ACM-ICPC参赛者人手一册
内容简介
书籍
计算机书籍
《挑战程序设计竞赛(第2版)》对程序设计竞赛中的基础算法和经典问题进行了汇总,分为准备篇、初级篇、中级篇与高级篇4章。作者结合自己丰富的参赛经验,对严格筛选的110 多道各类试题进行了由浅入深、由易及难的细致讲解,并介绍了许多实用技巧。每章后附有习题,供读者练习,巩固所学。
《挑战程序设计竞赛(第2版)》适合程序设计人员、程序设计竞赛爱好者以及高校计算机专业师生阅读。
作译者
秋叶拓哉,Google Code Jam 2010 第9名;ACM-ICPC World Finals 2012 第11名;TopCoder Open 2012 Algorithm 第4名,昵称iwi
岩田阳一,Google Code Jam 2009 第3名;TopCoder Open 2010 Marathon 冠军;IPSC 2010 个人组 冠军,昵称wata
北川宜稔,ACM-ICPC World Finals 2010第16名,昵称kita_masa
巫泽俊,ACM-ICPC World Finals 2009 第6名;ACM-ICPC World Finals 2011 冠军;Google Code Jam 2012 第7名,昵称watashi和rejudge
庄俊元,ACM-ICPC Asia Phuket Regional 2011 冠军;2012年跻身ACM-ICPC World Finals以及百度Astar总决赛,昵称navi和navimoe
李津羽,浙江大学2011级计算机系博士生,在浙大CAD&CG实验室从事科研工作
目录
《挑战程序设计竞赛(第2版)》
第1章 蓄势待发——准备篇 1
1.1 何谓程序设计竞赛 2
1.2 最负盛名的程序设计竞赛 5
1.2.1 世界规模的大赛——Google Code Jam(GCJ) 5
1.2.2 向高排名看齐!——TopCoder 5
1.2.3 历史最悠久的竞赛—— ACM-ICPC 6
1.2.4 面向中学生的信息学奥林匹克竞赛——JOI-IOI 6
1.2.5 通过网络自动评测——Online Judge(OJ) 6
1.3 本书的使用方法 7
1.3.1 本书所涉及的内容 7
1.3.2 所用的编程语言 7
1.3.3 题目描述的处理 7
1.3.4 程序结构 7
1.3.5 练习题 8
1.3.6 读透本书后更上一层楼的练习方法 8
1.4 如何提交解答 9
1.4.1 POJ的提交方法 9
1.4.2 GCJ的提交方法 11
1.5 以高效的算法为目标 15
1.5.1 什么是复杂度 15
1.5.2 关于运行时间 15
1.6 轻松热身 16
1.6.1 先从简单题开始 16
1.6.2 POJ的题目Ants 18
1.6.3 难度增加的抽签问题 20
第2章 初出茅庐——初级篇 25
2.1 最基础的“穷竭搜索” 26
2.1.1 递归函数 26
2.1.2 栈 27
2.1.3 队列 28
2.1.4 深度优先搜索 29
2.1.5 宽度优先搜索 33
2.1.6 特殊状态的枚举 37
2.1.7 剪枝 38
2.2 一往直前!贪心法 39
2.2.1 硬币问题 39
2.2.2 区间问题 40
2.2.3 字典序最小问题 43
2.2.4 其他例题 45
2.3 记录结果再利用的“动态规划” 51
2.3.1 记忆化搜索与动态规划 51
2.3.2 进一步探讨递推关系 57
2.3.3 有关计数问题的DP 66
2.4 加工并存储数据的数据结构 70
2.4.1 树和二叉树 70
2.4.2 优先队列和堆 71
2.4.3 二叉搜索树 77
2.4.4 并查集 84
2.5 它们其实都是“图” 91
2.5.1 图是什么 91
2.5.2 图的表示 94
2.5.3 图的搜索 97
2.5.4 最短路问题 99
2.5.5 最小生成树 105
2.5.6 应用问题 107
2.6 数学问题的解题窍门 113
2.6.1 辗转相除法 113
2.6.2 有关素数的基础算法 117
2.6.3 模运算 121
2.6.4 快速幂运算 122
2.7 一起来挑战GCJ的题目(1) 125
2.7.1 Minimum Scalar Product 125
2.7.2 Crazy Rows 127
2.7.3 Bribe the Prisoners 129
2.7.4 Millionaire 132
第3章 出类拔萃——中级篇 137
3.1 不光是查找值!“二分搜索” 138
3.1.1 从有序数组中查找某个值 138
3.1.2 假定一个解并判断是否可行 140
3.1.3 最大化最小值 142
3.1.4 最大化平均值 143
3.2 常用技巧精选(一) 146
3.2.1 尺取法 146
3.2.2 反转(开关问题) 150
3.2.3 弹性碰撞 158
3.2.4 折半枚举(双向搜索) 160
3.2.5 坐标离散化 164
3.3 活用各种数据结构 167
3.3.1 线段树 167
3.3.2 Binary Indexed Tree 174
3.3.3 分桶法和平方分割 183
3.4 熟练掌握动态规划 191
3.4.1 状态压缩DP 191
3.4.2 矩阵的幂 199
3.4.3 利用数据结构高效求解 206
3.5 借助水流解决问题的网络流 209
3.5.1 最大流 209
3.5.2 最小割 212
3.5.3 二分图匹配 217
3.5.4 一般图匹配 220
3.5.5 匹配、边覆盖、独立集和顶点覆盖 221
3.5.6 最小费用流 222
3.5.7 应用问题 228
3.6 与平面和空间打交道的计算几何 250
3.6.1 计算几何基础 250
3.6.2 极限情况 255
3.6.3 平面扫描 258
3.6.4 凸包 260
3.6.5 数值积分 263
3.7 一起来挑战GCJ的题目(2) 267
3.7.1 Numbers 267
3.7.2 No Cheating 269
3.7.3 Stock Charts 271
3.7.4 Watering Plants 273
3.7.5 Number Sets 278
3.7.6 Wi-fi Towers 280
第4章 登峰造极——高级篇 285
4.1 更加复杂的数学问题 286
4.1.1 矩阵 286
4.1.2 模运算的世界 291
4.1.3 计数 295
4.1.4 具有对称性的计数 300
4.2 找出游戏的必胜策略 305
4.2.1 游戏与必胜策略 305
4.2.2 Nim 311
4.2.3 Grundy数 315
4.3 成为图论大师之路 320
4.3.1 强连通分量分解 320
4.3.2 2-SAT 324
4.3.3 LCA 328
4.4 常用技巧精选(二) 335
4.4.1 栈的运用 335
4.4.2 双端队列的运用 337
4.4.3 倍增法 345
4.5 开动脑筋智慧搜索 350
4.5.1 剪枝 350
4.5.2 A*与IDA* 356
4.6 划分、解决、合并:分治法 359
4.6.1 数列上的分治法 359
4.6.2 树上的分治法 360
4.6.3 平面上的分治法 364
4.7 华丽地处理字符串 368
4.7.1 字符串上的动态规划算法 368
4.7.2 字符串匹配 373
4.7.3 后缀数组 378
4.8 一起来挑战GCJ的题目(3) 387
4.8.1 Mine Layer 387
4.8.2 Year of More Code Jam 392
4.8.3 Football Team 395
4.8.4 Endless Knight 399
4.8.5 The Year of Code Jam 403
本书中未涉及的拓展主题 408
书中例题列表 411
参考文献 413
译者序
程序设计竞赛因其涉及的知识面广,比赛形式激烈有趣,吸引了越来越多的学生参与其中。参赛者不但可以从中锻炼算法设计能力,还能够提高代码编写能力。其中的佼佼者也受到了越来越多国际知名公司的重视和欢迎。
本书的几位作者是世界公认的顶尖选手,在竞赛和学术领域都取得了令人瞩目的成就。他们结合自己的专业知识和比赛经验,将自己的心得和技巧集结成书。
全书将不同的算法和例题按专题编排成小节,再将不同的小节由易到难分成四章,这样即便是初出茅庐的新手也不会有太大的阅读障碍。书中涵盖了在程序设计竞赛中会用到的大多数算法和技巧,并在附录中补充了书中未介绍但也比较有用的算法。在题材的安排上,作者取舍得当,主次分明,循序渐进,不以华而不实的奇技淫巧误导读者,又具有一定深度,相信即便是经验丰富的老将同样能从书中有所斩获。本书在结合例题进行讲解时,不是简单地堆砌问题和代码,而是注重引导读者更好地理解和运用算法来分析解决问题。对于正在学习数据结构与算法的读者而言,把它作为一本练习和拓展的参考书也是很好的选择。
本书在日本广受好评,还先后在台湾地区和韩国出版。近年来程序设计竞赛在亚洲发展很快,在中国大陆也出版了不少相关书籍,但鲜见高质量的佳作。所以,在读到此书时,我们非常惊喜,迫切希望中国大陆也能引进这样的好书。2012年初,我们通过作者的推特了解到了本书第二版的出版,一些前辈们踊跃翻译计算机专业书籍的经历也鼓舞了我们,让我们萌生了亲自翻译此书的念头并联系了图灵教育。非常幸运的是,图灵教育也正考虑引进此书,于是有了今天呈现在各位读者面前的简体中文版。
在翻译上,我们力求做到既尊重国内选手的习惯,又符合计算机专业的表述。在修正原书中的一些笔误的同时,加入了一些译者注,以方便国内读者理解。但由于译者水平有限,不足之处在所难免,还望读者多多包涵,并不吝提出意见和建议。
在翻译过程中,秋叶拓哉、岩田阳一和北川宜稔三位作者耐心地对我们的一些疑问和笔误给予了一一解答和确认。浙江大学的陈越、王灿和翁恺三位老师不但将我们领进了“快乐”竞赛的大门,还拨冗审阅了译稿并提出了宝贵的意见。网上不少同好也对本书的出版给予了关切和支持。在此谨对他们表示感谢。
巫泽俊 庄俊元 李津羽
2013年5月6日于浙江大学
前言
如今,形形色色的程序设计竞赛层出不穷,听说过Google Code Jam、TopCoder、ACM-ICPC的读者恐怕不在少数。本书要介绍的正是这类以在规定时间内、又快又准地解决尽可能多的题目为目标的程序设计竞赛。
程序设计竞赛内涵丰富,即便是经验老道的程序员,要想在比赛中取得好成绩也绝非易事。要在程序设计竞赛中取胜,不仅需要运用灵活的想象和丰富的知识得出正确的算法,还需要一气呵成地实现并调试通过。
另一方面,程序设计竞赛对新手而言亦非遥不可及。为了让更多的参赛选手体会到比赛的乐趣,大多数比赛都会准备若干面向初学者的题目。另外,即便未能在比赛中取得好成绩,通过比赛,也能够使自己的能力得到有效的锻炼。最重要的是,大家能够享受到激烈的比赛带来的乐趣。
本书的作者们参加过众多程序设计竞赛,在平时的练习和学习中,也获得了各种各样的知识与技巧,本书将这些知识技巧总结成册,主要介绍算法及其在相关问题中的应用。本书依照由易及难的顺序对问题进行讲解,章节的编排也参考了主题的难易程度及其相互的联系,内容较多的主题则按难易程度划分为多个子主题分别介绍。各个主题由算法介绍和例题讲解穿插而成。
只要是具有编程基础知识的读者,均适合阅读本书。书中的源代码均用C++实现,不过只用到了其基本功能,所以即便读者不熟悉C++也不影响阅读。
关于再版
令人惊喜的是,本书的第1版受到了广大读者的高度评价,在此表示感谢。特别是一些并不热衷于程序设计竞赛的读者也购买了本书。这是因为通过本书不仅可以学到算法,更能学到其设计和运用的思想。这正是本书划时代的亮点。
本书第2版追加了计算几何、搜索减枝、分治法和字符串相关算法4个主题。此外还追加了方便读者加深理解的练习题,并为学有余力的读者列出了书中未涉及的拓展主题,进一步丰富了本书内容。
媒体评论
2.5.5 最小生成树
给定一个无向图,如果它的某个子图中任意两个顶点都互相连通并且是一棵树,那么这棵树就叫做生成树(Spanning Tree)。如果边上有权值,那么使得边权和最小的生成树叫做最小生成树(MST,Minimum Spanning Tree)。
例如我们假设有这样一个图:把顶点看作村庄,边看作计划要修建的道路。为了在所有的村庄间通行,恰好修建村庄数目—1条道路时的情形就对应了一棵生成树。修建道路需要投入建设费,那么求解使得道路建设费用最小的生成树就是最小生成树问题。
常见的求解最小生成树的算法有Kruskal算法和Prim算法。很显然,生成树是否存在和图是否连通是等价的,因此我们假定图是连通的。
1.最小生成树问题1(PrIm算法)
首先我们介绍Prim算法。Prim算法和Dijkstra算法十分相似,都是从某个顶点出发,不断添加边的算法。
首先,我们假设有一棵只包含一个顶点v的树T。然后贪心地选取T和其他顶点之间相连的最小权值的边,并把它加到T中。不断进行这个操作,就可以得到一棵生成树了。接下来我们来证明通过这个方法得到的生成树就是最小生成树。
书摘
2.5.5 最小生成树
给定一个无向图,如果它的某个子图中任意两个顶点都互相连通并且是一棵树,那么这棵树就叫做生成树(Spanning Tree)。如果边上有权值,那么使得边权和最小的生成树叫做最小生成树(MST,Minimum Spanning Tree)。
例如我们假设有这样一个图:把顶点看作村庄,边看作计划要修建的道路。为了在所有的村庄间通行,恰好修建村庄数目—1条道路时的情形就对应了一棵生成树。修建道路需要投入建设费,那么求解使得道路建设费用最小的生成树就是最小生成树问题。
常见的求解最小生成树的算法有Kruskal算法和Prim算法。很显然,生成树是否存在和图是否连通是等价的,因此我们假定图是连通的。
1.最小生成树问题1(PrIm算法)
首先我们介绍Prim算法。Prim算法和Dijkstra算法十分相似,都是从某个顶点出发,不断添加边的算法。
首先,我们假设有一棵只包含一个顶点v的树T。然后贪心地选取T和其他顶点之间相连的最小权值的边,并把它加到T中。不断进行这个操作,就可以得到一棵生成树了。接下来我们来证明通过这个方法得到的生成树就是最小生成树。