学习目标
掌握for循环、while循环、do-while循环的使用方法
学会使用计数器和累加器
学会用输出中间结果的方法调试
学会用计时函数测试程序效率
学会用重定向、fopen的方式读写文件
了解算法竞赛对文件读写方式和命名的严格性
记住变量在赋值之前的值是不确定的
学会使用条件编译指示构建本地运行环境
学会用编译选项-Wall获得更多的警告信息
2.1 for循环
例2-1 aabb
#include <stdio.h> int main() { /* 方法一 int i,j,m,n; for(i=1;i<10;i++) { for(j=0;j<10;j++) { m = i*1100+j*11; n = floor(sqrt(m)+0.5); //浮点运算可能存在误差,为了减小误差的影响,所以加上0.5,以便四舍五入。 if(n*n == m) { printf("%d\n",m); } } }*/ //方法二:枚举平方根,从而避免开平方操作 int i,n,a,b; for(i=1;;i++) { n = i*i; if(n>10000) { break; } if(n<1000) { continue; } a = n/100; b = n%100; if(a/10 == a%10 && b/10 == b%10) { printf("%d\n",n); } } return 0; }
2.2 while循环和do-while循环
例2-2 3n+1问题
#include <stdio.h> int main() { int n,count = 0; scanf("%d",&n); long long n1 = n; //int为32位的,long long为64位的,但它的输入输出比较复杂 while(n1>1) { if(n1%2 != 0) { n1 = 3*n1+1; }else{ n1 = n1/2; } count++; } printf("%d\n",count); return 0; }
/* 1.注意乘法溢出的问题
2.long long型
例2-3 近似计算
#include <stdio.h> int main() { int i; double sum = 0,term; for(i=0;;i++) { term = 1.0/(2*i+1); //注意应用1.0,使能够算出来浮点数 if(i%2 == 0) sum += term; else sum -= term; if(term<1e-6) break; } printf("%f\n",sum); return 0; }
2.3 循环的代价
例2-4 阶乘之和
#include <stdio.h> #include <time.h> int main() { const int MOD = 1000000; int n,i,a=1,b,sum=0; scanf("%d",&n); for(i=1;i<=n;i++) { a *= i; b = a%MOD; sum += b; } printf("%d\n",sum); printf("Time used = %.2f\n",(double)clock() / CLOCKS_PER_SEC); return 0; } /* 1.clock()函数返回程序目前为止运行的时间。常数CLOCK_PER_SEC和操作系统有关,不要直接使用clock()的返回值,而应总是除以这个常数。 2.上述得出的时间包括了键盘输入的时间。为了避免输入数据的时间影响测试结果,是使用一种称为“管道"的小技巧。 3.尝试很多次之后发现,从第五项开始,后面所有的项都不会影响和的末六位数字,所以只需在最前面加上“if(n>5) n=25;" 效率和溢出都不会存在问题。
例2-5 数据统计
#include <stdio.h> #define N 1000000 int main() { int max=-N,min=N,a,sum=0,i=0; while(scanf("%d",&a) == 1) { sum += a; if(a<min) min = a; if(a>max) max = a; i++; } printf("%d %d %.3f\n",max,min,(double)sum/i); retnrn 0; } //重定向版 #define LOCAL #include <stdio.h> #define N 1000000 int main() { #ifdef LOCAL freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif // LOCAL int max=-N,min=N,a,sum=0,i=0; while(scanf("%d",&a) == 1) { sum += a; if(a<min) min = a; if(a>max) max = a; i++; } printf("%d %d %.3f\n",max,min,(double)sum/i); return 0; } //fopen版 #include <stdio.h> #define N 1000000 int main() { FIFE *fin,*fout; fin = fopen("data.in","rb"); fout = fopen("data.out","wb"); int max=-N,min=N,a,sum=0,i=0; while(fscanf(fin,"%d",&a) == 1) { sum += a; if(a<min) min = a; if(a>max) max = a; i++; } fprintf(fout,"%d %d %.3f\n",max,min,(double)sum/i); fclose(fin); fclose(fout); return 0; } /* 1.输入数据,按enter键,并未显示结果,不是程序运行太慢,而是仍在等待输入。在Windows下,输入完毕后先按Enter键,再按Ctrl+Z键, 最后再按Enter键即可结束输入。在Linux下,输入完毕后按Ctrl+D键即可结束输入。 2.使用文件最简单的方法是使用输入输出重定向,只需在main函数的入口处加上以下两条语句: freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); 3.如果比赛要求用文件输入输出,但禁止使用重定向的方式,则可以使用fopen。 4.重定向和fopen两种方法各有优劣。 重定向:写起来自然、简单,但是不能同时读写文件和标准输入输出。 fopen:写法稍显繁琐,但是灵活性比较大(例如,可以反复打开并读写文件)。如果想把fopen版的程序改成读写标准输入输出, 只需赋值"fin=stdin;fout=stdout;"即可,不要调用fopen和fclose。 */
例2-6 数据统计II
#include <stdio.h> #define N 10000000 int main() { int n,a,k=0,i,max=-N,min=N,sum; while(scanf("%d",&n) == 1 && n) { max=-N,min=N; sum = 0; for(i=0;i<n;i++) { scanf("%d",&a); sum += a; if(a>max) max = a; if(a<min) min = a; } if(k) printf("\n"); printf("Case %d: %d %d %f\n",++k,min,max,(double)sum/n); } return 0; }