算法竞赛入门经典授课教案 循环结构程序设计.doc
《算法竞赛入门经典授课教案 循环结构程序设计.doc》由会员分享,可在线阅读,更多相关《算法竞赛入门经典授课教案 循环结构程序设计.doc(26页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第2章 循环结构程序设计【教学内容相关章节】2.1for循环 2.2循环结构程序设计 2.3文件操作2.4小结与习题【教学目标】1掌握for循环的使用方法;2掌握while循环的使用方法;3学会使用计算器和累加器;4学会用输出中间结果的方法调试;5学会用计时函数测试程序效率;6学会用重定向的方式读写文件;7学会fopen的方式读写文件;8了解算法竞赛对文件读写方式和命名的严格性;9记住变量在赋值之前的值是不确定的;10学会使用条件编译指示构建本地运行环境。【教学要求】掌握for循环的使用方法;掌握while循环的使用方法;掌握几个常用的文件操作库函数fopen、fclose、fprintf、f
2、scanf等。【教学内容提要】在有些程序中,需要反复执行某些语句。将n条相同的语句简单地复制会使程序变得不合理的冗长,因此高级语言中提供了支持程序重复执行某一段程序的循环控制语句。相关的语句有:for、while、do while、break、continue等。既可以从文件中读取数据, 也可以向文件中写入数据。读写文件之前,首先要翻开文件。读写文件结束后,要关闭文件。C/C+提供了一系列库函数,声明于stdio.h中,用于进行文件操作。这里介绍其中几个常用的文件操作库函数fopen、fclose、fprintf、fscanf等。【教学重点、难点】教学重点:1掌握for循环的使用方法;2掌握w
3、hile循环的使用方法;3掌握文件有关操作;4条件编译。教学难点:1掌握for循环的使用方法;2掌握while循环的使用方法;【课时安排共2学时】2.1for循环 2.2循环结构程序设计 2.3文件操作2.4小结与习题2.1 for循环请用for循环实现输入正整数n,打印1,2,3,10,每个占用一行。程序如下:程序2-1 输出1,2,3,n的值#include int main() int i, n; scanf(%d, &n); for(i = 1; i = n; i+) printf(%dn, i); return 0;提示2-1:for循环的格式:for(初始化;条件;调整) 循环体;
4、提示2-2:尽管for循环反复执行相同的语句,但这些语句每次的执行效果往往不同。提示2-3:编写程序时,要特别留意“当前行的跳转和变量的改变。有了for循环,可以解决一些简单的问题。例2-1 aabb。输出所有形如aabb的四位完全平方数即前两位数字相等,后两位数字也相等。【分析】分支和循环结合在一起时威力特别强大:可以枚举所有可能的aabb,然后判断它们是否是完全平方数。注意,a的范围是19,但b可以是0。主程序如下:for(a = 1; a = 9; a+) for(b = 0; b = 9; b+) if(aabb是完全平方数) printf(%dn, aabb);注意:1上面不是真正的
5、程序,把这样的代码称为伪代码psedocode。2上面用到了循环的嵌套:for循环的循环体自身又是一个循环。提示2-4:不拘一格的使用伪代码来思考和描述算法是一种值得推荐的做法。提示2-5:把伪代码改写成代码时,一般先选择较为容易的任务来完成。程序2-2 7744问题1#include #include int main() int a, b, n; double m; for(a = 1; a = 9; a+) for(b = 0; b = 9; b+) n = a*1100 + b*11; m = sqrt(n); if(floor(m+0.5) = m) printf(%dn, n);
6、return 0;说明:函数floor(x)返回x的整数局部,使用floor(m+0.5)=m的原因是浮点数的运算和函数有可能存在误差。提示2-6:浮点运算可能存在误差。在进行浮点数比拟时,应考虑到浮点误差。对于四位完全平方数的还有另一个思路就是枚举平方根x,从而防止开平方操作。程序2-3 7744问题2#include int main() int x, n, hi, lo; for(x = 1; ; x+) n = x * x; if(n 9999) break; hi = n / 100; lo = n % 100; if(hi/10 = hi%10 & lo/10 = lo%10) p
7、rintf(%dn, n); return 0;说明:本程序中用到break和continue语句。break是指直接跳出本层循环,continue是指结束本次循环,但不跳出本层循环,进入下一次循环。2.2 循环结构程序设计例2-2 3n+1问题。猜测:对于任意大于1的自然数,假设n为奇数,那么将n变为3n+1,否那么变为n的一半。经过假设干次这样的变换,一定会使n变为1。例如3105168421。输入n,输出变换的次数。n109。样例输入:3样例输出:7【分析】从3n+1问题可以看出,n也不是“递增式的循环,且循环次数也不确定,这种情况非常适合用while循环来实现。程序2-4 3n+1问题
8、#include int main() int n, count = 0; scanf(%d, &n); while(n 1) if(n % 2 = 1) n = n*3+1; else n /= 2; count+; printf(%dn, count); return 0;提示2-7:while循环的格式为:“while(条件) 循环体;。从程序2-4中可得,while循环与for循环可以相互转化。在本程序中的count+,相当于一个计算器,这个功能在编程中会经常遇到。提示2-8:当需要统计某种事物的个数时,可以用一个变量来充当计算器。提示2-9:不要忘记测试。一个看上去正确的程序可能隐含
9、错误。提示2-10:在观察无法找出错误时,可以用“输出中间结果的方法查错。例2-3 阶乘之和。输入n,计算S=1!+2!+3!+n!的末6位不含前导0。n106。这里,n!表示前n个正整数之积。样例输入:10样例输出:37913【分析】用S变量来累加阶乘之和。核心算法只有一句话:for(i=1;i=n;i+) S+=i!。在C语言中没有阶乘运算符,所以还需要一个循环来求i!: for(j=1;j=i;j+) factorial*=j;。 代码如下:程序2-5 阶乘之和1#include int main() int i, j, n, S = 0; scanf(%d, &n); for(i =
10、1; i = n; i+) int factorial = 1; for(j = 1; j = i; j+) factorial *= j; S += factorial; printf(%dn, S % 1000000); return 0;注意:每执行一次循环体,都要重新声明一次累乘器factorial,并初始化为1因为是乘积,所以初始化为1,要是初始化为0,那么循环后的factorial=i!=0。提示2-11:在循环体开始处定义的变量,每次执行循环体时会重新声明并初始化。提示2-12:要计算只包含加法、减法和乘法的整数表达式除以正整数n的余数,可以在每步计算之后对n取余,结果不变。程序
11、2-6 阶乘之和2#include #include int main() const int MOD = 1000000; int i, j, n, S = 0; scanf(%d, &n); for(i = 1; i = n; i+) int factorial = 1; for(j = 1; j = i; j+) factorial = (factorial * j % MOD); S = (S + factorial) % MOD; printf(%dn, S); printf(Time used = %.2lfn, (double)clock() / CLOCKS_PER_SEC);
12、 return 0;说明:1这个程序真正的特别之处在于计时函数clock()的使用。该函数返回程序目前为止运行的时间,以毫秒为单位。这样,在程序结束之前调用它,便可获得整个程序的运行时间。这个时间除以常数CLOCKS_PER_SEC之后得到的值以“秒为单位。2在VC+6.0中time.h下宏定义的常量CLOCKS_PER_SEC,其值为1000。VC+6.0中该符号常量定义如下: #define CLOCKS_PER_SEC 1000对于CLOCKS_PER_SEC,它用来表示一秒钟会有多少个时钟计时单元,时钟计时单元的长度为1毫秒,clock()/CLOCKS_PER_SEC就是将毫秒转化为
13、秒。提示2-13:可以使用time.h和clock()函数获得程序运行时间。常数CLOCKS_PER_SEC与操作系统有关,请不要直接使用clock()的返回值,而应总是除以CLOCKS_PER_SEC。提示2-14:很多程序的运行时间与规模n存在着近似的简单关系。可以通过计时函数来发现或验证这一关系。 本节的两个例题展示了计数器、累加器的使用和循环结构程序设计中最常见的两个问题:算术运算溢出和程序效率低下。另外,本节中介绍的两个工具输出中间结果和计时函数,都有是相当实用的。2.3 文件操作例2-4 数据统计。输入一些整数,求出它们的最小值、最大值和平均值保存3位小数。输入保证这些数都是不超过
14、1000的整数。样例输入:2 8 3 5 1 7 3 6样例输出:1 8 4.375【分析】如果是先输入整数n,然后输入n个整数,相信能写出程序。关键在于:整数的个数是不确定的。下面给出程序:程序2-7 数据统计错误#include int main() int x, n = 0, min, max, s = 0; while(scanf(%d, &x) = 1) s += x; if(x max) max = x; n+; printf(%d %d %.3lfn, min, max, (double)s/n); return 0;说明:1scanf函数的返回值是成功输入的变量个数。当输入结束
15、时,scanf无法再次读取x,将返回0。2在测试时,输入2 8 3 5 1 7 3 6,按Enter键后,没有输出结果,所以此时按Enter键并不意味着输入的结束。提示2-15:在Windows下,输入完毕后先按Enter键,再按Ctrl+Z键,最后再按Enter键,即可结束键入。在Linux下,输入完毕后按Ctrl+D键即可结束输入。通过提示2-15,输入可以结束了。但是此程序的运行结果是不确定的。提示2-16:变量在未赋值之前的值是不确定的。特别地,它不一定等于0。解决上面程序的运行结果不对的方法是在变量使用前赋初值。由于min保存的是最小值,它的初值应该是一个很大的数;反过来,max的初
16、值应该是一个很小的数。一种方法是定义一个很大的常数,如INF=1000000000,然后让max=INF,而min=-INF,而另一种方法是先读取第一个整数x,然后令max=min=x。另一个好的方法是用文件把输入数据保存在文件中,输出数据也保存在文件中。事实上,几乎所有算法竞赛的输入数据和标准答案都是保存在文件中的。使用文件最简单的方法是使用输入输出重定向,只需要在main函数的入口处参加以下两条语句:freopen(input.txt,r,stdin);freopen(output.txt,w,stdout);它将使得scanf从文件input.txt读入,printf写入文件output
17、.txt。但是并不是所有算法竞赛都允许用程序读写文件。甚至有的竞赛允许访问文件,但不允许freopen这样的重定向方式读写文件。请参赛之前仔细阅读文件读写的相关规定。提示2-17:请在比赛之前了解文件读写的相关规定:是标准输入输出也称标准I/O,即直接读键盘、写屏幕,还是文件输入输出?如果是文件输入输出,是否禁止用重定向方式访问文件?多年来,无数选手因文件相关问题丢掉了大量的得分。一个普适的原那么是:详细阅读比赛规定,并严格遵守。例如,如果题目规定程序名称为test,输入文件名为test.in,输出文件名为test.out,就是不要犯以下错误。错误1:程序存为t1.c应该改成test.c。 错
18、误2:从input.txt读取数据应该从test.in读取。 错误3:从tset.in读到数据拼写错误,应该从test.in读取。 错误4:数据写到test.ans扩展名错误,应该是test.out。 错误5:数据写到c:contesttest.out不能加路径,哪怕是相对路径。文件名应该只有8个字符:test.out。提示2-18:在算法竞赛中,选手应严格遵守比赛的文件名规定,包括程序文件名和输入输出文件名。不要弄错大小写,不要拼错文件名,不要使用绝对路径或相以路径。 利用文件是一种好的自我测试方法,但如果比赛要求采用标准输入输出,就必须在自我测试完毕之后删除重定向语句。下面来介绍一种方法可
19、以在本机测试时用文件重定向,但一旦提交到比赛,就自动“删除重定向语句。代码如下:程序2-8 数据统计重定向版#define LOCAL#include #define INF 1000000000int main()#ifdef LOCAL freopen(data.in, r, stdin); freopen(data.out, w, stdout);#endif int x, n = 0, min = INF, max = -INF, s = 0; while(scanf(%d, &x) = 1) s += x; if(x max) max = x;/* printf(x = %d, mi
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法竞赛入门经典授课教案 循环结构程序设计 算法 竞赛 入门 经典 授课 教案 循环 结构 程序设计
限制150内