2.3 循环的代价
- 例题2-4阶乘之和
输入n,计算s=1!+2!+3!+…+n!。n<=le-6。
样例输入:
10
样例输出:
37913
//第一个版本
int main()
{
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*=j;
}
S+=factorial;
printf("%d\n",s%1000000);
}
}
- 要计算只包含加法,减法和乘法的整数表达式除以正整数n的余数,可以在每步计算之后对n取余,结果不变
//第二个版本
#include<time.h>
#include<stdio.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=(factorial*j%MOD);
}
s=(s+factorial)%MOD;
}
printf("%d\n",s);//其实从第五项开始后面的所有项都不会影响和的末6位数字这样就可解决效率和溢出
printf("time used=%.2f\n",(double)clock()/CLOCKS_PER_SEC);//计时器的使用
return 0;
}
- 很多程序的运行时间与规模n存在着近似的简单关系。可以通过计时函数来发现或验证这一关系
2.4算法竞赛中的输入输出框架
- 例题2-5 数据统计
输入一些整数求出它们的最小值,最大值和平均值(保留三位小数)。输入保证这些数都是不超过1000的整数
样例输入:
2 8 3 5 1 7 3 6
样例输出:
1 8 4.375
//有bug版本
#include<stdio.h>
int main()
{
int x,n=0,min,max,s=0;
while(scanf("%d",&x)==1)//scanf函数返回的是成功输入的变量个数,
//当输入结束时scanf函数无法再次读取x将返回0
//按下enter建并不意味着输入的结束
{
s+=x;
if(x<min) min=x;//在使用前未赋值
if(x>max) max=x;
n++;
}
printf("%d %d %.3f\n",min,max,(double)s/n);
return 0;
//第一种方法是定义一个很大的常数如inf=1000000000,然后让max=-inf而min=inf
//另一种就是先读取一个整数x然后令max=min=x
}
- 在Windows下输入完毕后先按enter键再按ctrl+z键,最后再按enter键即可输入结束。在linux下输入完毕后按ctrl+d键即可结束输入
- 变量在未赋值之前的值是不确定的。特别地,它不一定等于0.
- 请在比赛之前了解文件读写的相关规定:是标准输入输出,还是文件输入输出?如果是文件输入输出,是否禁止用重定向方式访问文件
请不要犯以下错误
1:程序存为t1.c(应该改为test.c)
2:从input.txt读取数据(应该从test.in读取)
3:从test.in读取数据(拼写错误)
4:数据写到test.ans(扩展名错误,应该是test.in读取)
5:数据写到c:\contest\test.out(不能加路径哪怕是相对路径。文件名应该只有test.out)
//这是一份典型的比赛代码(重定向版)
#include<stdio.h>
#define LOCAL
#define INF 1000000000
int main()
{
#ifdef LOCAL//重定向的部分
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
#endif // LOCAL
int x,n=0,min=INF,max=-INF,s=0;
while(scanf("%d",&x)==1){
s+=x;
if(x<min) min=x;
if(x>max) max=x;
/*
printf("%d,%d,%d\n",x,min,max);*///也是一个重点
n++;
}
printf("%d %d %.3f\n",min,max,(double)s/n);
return 0;
}
- 在算法竞赛中有经验的选手往往会使用条件编译指令并且将重要的测试语句注释掉而非删除
//fopen版本即要求文件输入输出但禁止重定向的方式
#include<stdio.h>
#define INF 1000000000
int main()
{
FILE *fin,*fout;
fin=fopen("data.in","rb");
fout=fopen("data.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("%d %d %.3f\n",min,max,(double)s/n);
fclose(fin);
fclose(fout);
return 0;
}
- 在算法竞赛中如果不允许使用重定向方式读写数据应使用fopen和fscanf/fprintf进行输入输出
- 例题2-6 数据统计||
输入一些整数求出它们的最小值,最大值和平均值(保留三位小数)。输入保证这些数都是不超过1000的整数
输入包含多组数据,每组数据第一行是整数个数n第二行是n个整数。n=0为输入结束标记,程序应当忽略这组数据。相邻两组数据之间应输出一个空行
样例输入:
8
2 8 3 5 1 7 3 6
4
-4 6 10 0
0
样例输入:
case 1:1 8 4.375case 2:-4 10 3.000
//有bug
#include<stdio.h>
#define INF 1000000000
int main()
{
int x,n=0,min=INF,max=-INF,s=0,kase=0;//min和max没用重置导致bug//kase为了格式需求
while(scanf("%d",&n)==1&&n)//为了鲁棒性
{
int s=0;//把main函数里定义的“屏蔽了”
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 %.3f\n",++kase,min,max,(double)s/n);
}
return 0;
}
- 在算法竞赛中,偶尔会出现输入输出错误的情况。如果程序鲁棒性强有时能在数据有瑕疵的情况下仍然给出正确的答案。程序的鲁棒性在工程中也非常重要
- 再多数据的题目中常见错误:在计算完一组数据后某些变量没有重置,影响到下组数据的求解
- 当嵌套的两个代码块中有同名变量时,内层的变量会屏蔽外层变量,有时会引起十分隐蔽的错误