循环结构
2-1 for:
tips:
- 在循环体里查看变量变化可以使用断点和watch功能。
- 缩短循环变量定义范围,如在for(int i = 0;xxxx;xxxx),在初始化部分就定义循环变量
1.aabb完全平方数:
输出形如aabb的4位完全平方数(n**2):
//方法一:
for(int i = 1; i <= 9; i++)
for(int j = 0; j <= 9; j++){ //i的范围是1-9,j的范围是0-9
int n = i*1100 + j*11; //n表示形如aabb的数
int m = floor(sqrt(n) + 0.5); //四舍五入
if(m*m == n) printf("%d",n);
}
解释:用n来表示形如aabb的数,m表示n开完平方根的整数,判断m*m是否=n
tips:
- floor(x) 函数:返回不超过x的最大整数
- floor( x + 0.5):四舍五入,相当于把一个单位区间在数轴上向右移动了0.5的距离,例如:floor(x)=1的区间为[1,2)
- 浮点数运算可能存在误差,故进行浮点数比较时,一定要考虑误差。
//方法二:枚举平方根x
for(int x = 1; ; x++){
int n = x*x;
if(n < 1000) continue;
if(n > 9999) break; //确定四位数的范围
int high = n / 100; // aa
int low = n % 100; // bb
if(high/10 == high%10 && low/10 == low%10) printf("%d",n);
}
2-2while 和 do-while :
本小节介绍了循环结构的代价
最常见的两个问题:算术溢出和程序效率低下。
最常用的两个工具:输出中间结果和计时函数。(分别对应溢出检查和效率检查)
阶乘之和
输入n,计算S=1!+2!+3!+…+n!的末6位。n<=10**6
#include<stdio.h>
#include<time.h>
int main(){
const int MOD = 1000000;
int n, S = 0;
scanf("%d",&n);
for(int i = 1; i <= n; i++){
int factorial = 1;
for(int j = 1; j <= i; j++){
factorial = (factorrial * j % MOD);
}
S = (S +factorial) % MOD;
}
printf("time used = %.2f\n",(double)clock() / CLOCK_PER_SEC);// / CLOCK_PER_SEC代表单位为“秒”
}
/*clock() / CLOCK_PER_SEC:在程序结束之前调用此函数可以获得整个程序的运行时间,
减少程序运行时间的方法:
可知计算到25!时末尾有6个0,所以在第5项开始,后边所有项都不会影响末6位数字。–只需要在程序前加上 if(n > 25)n = 25;效率和溢出问题都会解决
2-3 竞赛中的输入和输出框架
tips:
- 变量在未赋值之前,值是不确定的。所以声明时最好赋初值。
-
标准输入输出下的 结束输入:
Windows下,输入完毕后先按 Enter ,再按 Ctrl+Z ,最后再按Enter 可以结束输入。 -
务必了解比赛规定!
有的时候可以用文件来储存输入数据和输出数据,便于文件的比较。
需要注意文件读写规定:
是I/O方式(直接读键盘、写屏幕),还是文件输入输出?
如果是文件输入输出,那是否禁止用重定向方式访问文件?
遵守文件名规定:
包括程序文件名和输入输出文件名。注意大小写,不要拼错文件名,不要使用相对路径或者绝对路径。
数据统计:
输入一些整数,求他们的最小值,最大值和平均值(保留三位小数),输入的这些数是保证不超过1000的整数。
a.重定向版
#define LOCAL
#include<stdio.h>
#define INF 1000000000
int main(){
#ifdef LOCAL
freopen("date.in","r",stdin);
freopen("date.out","w".stdout);
#endif
int x,n = 0, min = INF,max = -INF,s = 0;
while (scanf("%d",&x) == 1){ //scanf()返回的是输入元素的个数,输入结束后无法再读取x,将返回0
s += x;
if(x < min) min = x;
if(x > max) max = x;
/*
printf("x = %d, min =%d, max =%d",x,min,max);
*/
n++;
}
printf("%d %d %0.3f",min,max.(double)s/n);
}
#ifdef和#endif:重定向部分,含义是:只有定义了LOCAL符号才能进行读写。
输出中间结果的printf部分可以写在注释里,需要用的时候只需要把注释符号删掉。
把LOCAL符号写在首行,如果比赛要求读写标准输入输出,提交程序时方便删除。
当然,注释掉要比定义LOCAL方便。
b.fopen版(若不让用重定向方式)
#include<stdio.h>
#define INF 1000000000
int main(){
FILE *fin, *fout;
fin = fopen("date.in","rb");
fout = fopen("date.out","wb");
int x,n = 0, min = INF,max = -INF,s = 0;
while (fscanf(fin,"%d",&x) == 1){
s += x;
if(x < min) min = x;
if(x > max) max = x;
n++;
}
fprintf(fout,"%d %d %0.3f\n",min,max.(double)s/n);
fclose(fin);
fclose(fout);
}
- 先声明变量fin和fout,
- 把scanf改成fscanf,并且第一个参数是fin;把printf改成fprintf,并且第一个参数为fout。
- 最后执行fclose关闭两个文件
c.两种方式的比较:
重定向 | fopen |
---|---|
简单 | 繁琐 |
不能同时读写文件和用I/O | 灵活,可以反复打开读写文件 |
需要define符号;使用freopen;和stdin和stdout | 需要定义读文件写文件变量;使用fopen();输入输出时用fscanf、fprntf并且第一个参数为对应的变量;需要用fclose()关闭文件 |
不能用标准输入输出方式 | 可以用,只需赋值fin=stdin;fout=stdout;另外不要调用fopen和fclose |
多数据统计
指的是输入数据的文件里有多组数据
和上题一样,不过输入应包含多组数据,且输入整数 n=0 为输入结束标记,程序应当忽略这组数据,相邻两组数据间应输出一个空行。例如:
样例输入:
8
2 8 3 5 1 7 3 6
4
-4 6 10 0
样例输出:
case1:1 8 4.375
/空行/
case2:-4 10 3.000
#include<stdio.h>
#define INF 1000000000
int main(){
int x,n = 0, min = INF,max = -INF,s = 0,kase = 0;//kase为“当前数据编号”计数器
while (scanf("%d",&x) == 1 && n){ //&&n是因为 n=0是输入结束标记
int s = 0;
min = INF;
max = -INF; // max和min重置,否则会影响下组数据求解
for(int i = 0; i < n; i++){
scanf("%d",&x);
s += x;
if(x < min) min = x;
if(x > max) max = x;
}
if(kase) printf("\n");
printf("case%d: %d %d %0.3f\n", ++kase,min,max.(double)s/n);
}
- 当嵌套内外有同名变量时,内层变量会屏蔽外层变量,有时会引起十分隐蔽的错误。