本书遵循“精选案例,面向设计,深入浅出,注重能力培养”的要求,以案例形式实现算法与程序设计教学。本书精选了枚举、递推、递归、回溯、动态规划、贪心算法与模拟等常用算法,精选各算法求解的典型案例。每一个案例求解,从案例提出到算法设计,从程序实现到算法复杂度分析,环环相扣,融为一体,力求算法理论与实际应用相结合,算法与程序相统一,突出算法在解决实际问题中的核心地位与引导作用。书中所有案例求解给出详细的算法描述与完整的C程序,程序均在Visual C++ 6.0下编译通过,所有源代码均可从清华大学出版社网站下载。 本书可作为高等院校计算机及相关专业“算法设计与分析”、“程序设计基础与应用”等课程的教材,也可供软件设计人员与计算机爱好者学习参考。
计算机算法与程序设计是计算机科学与技术的核心,是大学计算机相关专业的一门重要专业基础课。通过我们对现有计算机本科专业“算法设计与分析”课程教学的调研分析,发现很多同学对学过的算法思路不明了,描述不清楚,设计不到位,无法应用算法设计程序解决一些常见的实际问题。缺少适合计算机本科层次的“算法与程序设计”教材是造成这一局面的重要原因之一。
一般现有“算法设计与分析”教材在算法选取上贪多求全、贪广求深,混杂一些难度大、理论深、应用少的带有学术研究性质、适宜研究生阶段的算法内容。同时这些教材普遍存在以下问题: 算法与数据结构结合多,而与程序设计结合少;罗列算法多,应用算法设计解决实际问题少;算法与程序设计脱节,算法理论与实际应用脱节,不利于算法设计的应用推广,也不利于学生应用算法与程序设计解决实际问题能力的提高。
为此,笔者在编著《计算机程序设计经典题解》(清华大学出版社,2007)与《计算机常用算法与程序设计教程》(“十一五”国家级规划教材,人民邮电出版社,2008)的基础上进行优化整合,推出适合本科“算法与程序设计”教学实际的案例教程。
本教程遵循“精选案例,面向设计,深入浅出,注重能力培养”的宗旨编写,在常用算法应用案例的选取与深度的把握上,在算法理论与案例求解的结合上进行精心设计,力图满足高校计算机本科教学目标与知识结构的要求。本书体现出以下五个特色。
(1) 以案例形式实现算法与程序设计教学。
学习算法与程序设计是为了培养提高学生应用算法与程序设计解决实际问题的能力,算法与程序设计课程教学无疑是最适宜以案例形式来实现的。通过典型案例来引导算法设计的逐步深入,实现以典型案例支撑算法,以算法设计指导案例求解的良性循环。
采用案例形式实现算法与程序设计教学在全国是首创,从案例提出到算法设计与程序实现,从案例结果讨论到算法改进与复杂度分析,环环相扣,融为一体,使学生看得见,摸得着,学得会,用得上,容易收到立竿见影、举一反三的效果。
(2) 注重常用算法的选取与组织。
在常用算法的选取上避免贪多求全、贪广求深,去除一些难度大、理论深、应用少的带有学术研究性质的算法内容,结合本科教学实际与应用需求,选取枚举、递推、递归、回溯、动态规划、贪心算法与模拟等常用算法。其中模拟算法中的“竖式运算模拟”是我们总结推广用于数论高精计算的创新成果。
对精选的各种常用算法,在介绍算法的基本理论与设计思路后,从实际案例的解决入手,讲述算法中要求本科学生掌握的基本思路、设计内容与实施步骤,避免出现本科阶段与研究生阶段的教学内容混杂不清,避免出现蜻蜓点水、面面俱到、空洞不实的局面。
(3) 注重典型案例的精选与提炼。
针对选取的每一种常用算法,精选典型的实际案例,包括典型的数值求解、常见的数据处理、有趣的智力测试以及巧妙的模拟探索,既有引导入门的基础案例,也有难度较大的综合案例,既有构思巧妙的新创趣题,也有历史悠久的经典名题,难度适宜,深入浅出。
培养学生的学习兴趣,激发学生的学习热情,提高学生的设计技能,不是一两句空洞说教所能奏效的,必须通过一系列有趣的实际案例来引导。本教程针对所精选的常用算法,设计了初等难度基础型、中等难度应用型、较高难度综合型三种梯度的案例。这些案例的精选与提炼,有利于提高学生学习算法与程序设计的兴趣,有利于学生在计算机实际应用上开阔视野,使之在算法思路的开拓与设计技能的运用上有一个深层次的锻炼与提高。其中难度较大的综合案例可作为相应课程的课程设计选用。
(4) 注重算法设计与程序实现的紧密结合。
算法与程序实际上是一个统一体,不应该也不可能将它们对立与分割。本教程在材料的组织上克服了罗列算法多,应用算法设计解决实际问题少,算法与程序设计脱节,算法理论与实际应用脱节的问题。在讲述每一种常用算法的基本思路与设计步骤的基础上,落实到每一个案例求解,从案例提出到算法设计、从程序实现到算法复杂度分析,环环相扣,融为一体,力求算法理论与实际应用相结合,算法与程序相统一,突出算法在解决实际问题中的核心地位与引导作用,切实提高学生对所学算法的理解和掌握。
本教程采用功能丰富、应用面广、高校学生使用率最高的 C语言来描述算法、编写程序。为使读者使用方便,程序均在Visual C++ 6.0下编译通过。
(5) 注重算法改进与程序优化。
本教程对一些典型案例应用多种不同的算法设计,编写不同表现形式与不同设计风格的程序,体现了算法与程序设计的灵活性和多样性。
算法与程序设计都不是一成不变的,可以实施多方位多层次的变通,变通出成果,变通长能力。算法改进与程序优化的过程,既是提高案例求解效率的过程,也是算法设计能力培养与提高的过程,更是优化意识与创新能力增强的过程。
为方便读者学习,附录中提供了部分习题求解提示,简介在Visual C++ 6.0环境下运行C程序的方法,并列出C语言常用函数。同时,本教程中的所有源程序与各章习题的完整代码均可在清华大学出版社网站(http://www.tup.com.cn)下载。
本教程适合各高校计算机相关本科专业“算法设计与分析”、“程序设计基础与应用”课程教学,并可供各级程序设计竞赛与ACM复习参考,也可供IOI、NOI培训选用。
在本书的编著修订过程中,湖南理工学院王岳斌教授、周持中教授、严权锋副教授与谭用秋博士等给予作者多方面的支持与帮助,刘志辉硕士阅读了全部书稿并运行了所有程序,作者在此一并深表感谢。
尽管每一案例求解都经反复核实检查,每一求解程序都经多次运行调试,但因涉及内容较广,书中难免存在差错,恳请读者批评指正。
杨克昌2014年6月于岳阳南湖
第1章算法与程序设计概述1
1.1算法及其描述1
1.1.1算法定义1
1.1.2算法描述3
1.2算法的复杂性分析7
1.2.1时间复杂度7
1.2.2空间复杂度12
1.3算法设计与分析示例13
1.3.1求解最大公约数13
1.3.2拆分为连续正整数之和15
1.3.3统计n!尾部零17
1.4算法与程序设计19
1.4.1算法与程序19
1.4.2结构化程序设计23
习题126第2章枚举28
2.1枚举概述28
2.2统计与求和29
2.2.1全素组30
2.2.2最简真分数32
2.3解方程33
2.3.1佩尔方程33
2.3.2超越方程35
2.4解不等式37
2.4.1分数不等式37
2.4.2代数和不等式38
2.5求最值41
2.5.1基于素数的代数和41
2.5.2整数的因数比43
2.6数组与序列44
2.6.1双和二组44
2.6.2和积三组46
2.6.3双码二部数序列47
2.7数式探求50
2.7.1逆序乘积式50
2.7.2完美综合式51
2.8趣味数阵55
2.8.1素数幻方55
2.8.2和积三角形58
2.9枚举应用小结60
习题265第3章递推66
3.1递推概述66
3.1.1递推算法66
3.1.2递推实施步骤与描述67
3.2超级素数搜索69
3.3递推数列72
3.3.1摆动数列72
3.3.2分数数列73
3.4幂序列75
3.4.1双幂序列75
3.4.2幂积序列76
3.5数阵与网格82
3.5.1杨辉三角82
3.5.2交通方格网84
3.6整数划分问题86
3.6.1整数划分递推设计86
3.6.2整数划分递推优化88
3.7水手分椰子问题90
3.7.15个水手分椰子90
3.7.2n个水手分椰子93
3.8猴子爬山94
3.8.1简单案例的具体递推95
3.8.2一般情形的分级递推95
3.9递推应用小结97
习题399第4章递归101
4.1递归概述101
4.2排队购票104
4.3汉诺塔问题106
4.3.1求移动次数106
4.3.2展示移动过程107
4.4旋转数阵109
4.4.1双转向旋转方阵109
4.4.2m行n列顺转矩阵111
4.5快速排序与选择114
4.5.1快速排序114
4.5.2分区交换选择117
4.6排列组合的实现119
4.6.1实现排列A(n,m)119
4.6.2实现组合C(n,m)121
4.6.3复杂排列123
4.7整数的拆分125
4.7.1拆分零数取自连续区间126
4.7.2拆分零数取自指定整数127
4.8递归应用小结129
习题4132第5章回溯法133
5.1回溯法概述133
5.1.1回溯的概念133
5.1.2回溯描述133
5.2桥本分数式137
5.2.1桥本分数式138
5.2.210数字分数式140
5.3直尺与串珠141
5.3.1古尺神奇141
5.3.2数码串珠144
5.4逐位整除数146
5.5环序列149
5.5.1素数和环150
5.5.2德布鲁金环151
5.6伯努利装错信封问题154
5.6.1装错信封问题154
5.6.2特殊错位探索157
5.7别出心裁的情侣拍照问题159
5.7.1逐位安排与回溯159
5.7.2成对安排与回溯161
5.8回溯应用小结163
习题5166第6章动态规划167
6.1动态规划概述167
6.1.1动态规划的概念167
6.1.2动态规划实施步骤168
6.2最长子序列探索169
6.2.1最长非降子序列169
6.2.2最长公共子序列172
6.3最优路径搜索175
6.3.1点数值三角形的最优路径175
6.3.2边数值矩形的最优路径177
6.4装载问题180
6.501背包问题183
6.5.1一般01背包问题184
6.5.2二维约束01背包问题188
6.6凸n边形的三角形划分190
6.7插入乘号问题193
6.8动态规划应用小结195
习题6198第7章贪心算法200
7.1贪心算法概述200
7.2删数字问题202
7.3埃及分数式205
7.3.1选择最小分母构建205
7.3.2贪心选择范围的扩展207
7.4可拆背包问题208
7.5数列操作与极差209
7.5.1数列操作210
7.5.2数列操作优化211
7.5.3数列极差212
7.6哈夫曼树及其应用215
7.6.1哈夫曼树215
7.6.2哈夫曼编码217
7.7贪心算法应用小结221
习题7222第8章模拟224
8.1模拟概述224
8.1.1模拟分类224
8.1.2竖式运算模拟227
8.2乘数探求229
8.2.1积为若干个1构成229
8.2.2积为若干个2015构成230
8.2.3积的任意指定构成231
8.3尾数前移问题233
8.3.1限1位尾数前移233
8.3.2多位尾数前移235
8.4阶乘幂与排列组合数的计算236
8.5圆周率计算238
8.5.1蒙特卡罗模拟计算238
8.5.2指定高精度计算239
8.6漫步坐标系241
8.7模拟发桥牌244
8.8泊松分酒问题247
8.9模拟应用小结250
习题8251第9章算法的综合应用253
9.1高斯皇后问题253
9.1.1高斯八皇后问题253
9.1.2n皇后问题255
9.1.3皇后全控棋盘问题259
9.2翻转硬币游戏263
9.2.1翻转m×9矩阵263
9.2.2翻转m×n矩阵266
9.2.3大规模矩阵求解270
9.3最优复杂路径探索273
9.3.1矩阵迷宫中的最短通道273
9.3.2三角数阵中的最小路径277
9.4马步遍历与哈密顿圈280
9.4.1马步遍历280
9.4.2马步型哈密顿圈287
9.4.3组合型哈密顿圈292
9.5综合应用小结299
习题9300附录A部分习题求解要点301附录B在Visual C++ 6.0环境下运行C程序方法简介315附录CC语言常用库函数320参考文献324