1、floor()函数
floor(x)
返回不超过x的最大整数
2、计算时间的函数
- 头文件
<time.h>
- 函数
clock()
返回程序目前为止运行的时间,调用此函数得到整个程序的运行时间,这个时间除以CLOCKS_PER_SEC
之后得到的值以秒为单位。
注意: - 常数
CLOCKS_PER_SEC
与操作系统相关,在使用时请不要直接使用clock()
函数,而应该总是除以CLOCKS_PER_SEC
- 若程序包含输入,则
clock()
函数计算的时间包括程序输入的时间,因为输入确实是在函数运行后进行的,所以如果想去除函数输入计算时间,可以采用命令行运行程序的方式echo 20|test
或者echo 20|./test
此时20是程序的输入,而test是程序的名字。
3、计算阶乘时数太大溢出的问题
- 若计算只包含加法、减法和乘法的整数表达式除以正整数n的余数,可以在每部计算后对n取余,结果不变。
如下例:
#include<iostream>
#include<ctime>
using namespace std;
int main(){
const int MOD = 1000000;
int n,S = 0;
cin>>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;
}
cout<<S<<endl ;
cout<<"Time used "<<(double)clock()/CLOCKS_PER_SEC;
return 0;
}
上例中使用const
关键字定义常数MOD
,每次进行+ - * /
后均除以MOD
的余数,结果是不变的,且可以防止溢出。
- const定义变量时表示表示该变量是不可变的,也就是常数的意思,在定义常数时最好采用该方式。
4、当不确定程序读入的个数时
while(scanf("%d",&x)==1){
s += x;
if(x<min)
min = x;
if(x>max)
max = x;
n++;
}
- 上述代码是是一个对n个元素求最大值、最小值并求和的函数,此时n的个数不确定,而让程序停止运行的方式就是
crtl z
,此时的scanf()
返回程序读入的变量的个数。
5、输入输出重定向
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
- 该语句可以讲
scanf
从文件input.txt
中输入,printf
写入文件output.txt
,所有的读键盘输入、写屏幕输出的函数都将改用文件。
注意:不是所有的算法竞赛都允许用程序读写文件,有的允许,也不一定允许采用重定向freopen
的方式读写文件,注意看题目。 - 当比赛不允许使用文件重定向输入输出时,使用文件进行测试仍然是一个很好的办法,此时可以采用以下程序在本机测试时采用文件重定向,一旦提交到比赛就自动删除重定向语句,代码如下:
#include<iostream>
#define LOCAL
#include<ctime>
using namespace std;
int main(){
const int INF = 100000000;
int x,n=0,min=INF,max=-INF,s=0;
#ifdef LOCAL
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
while(scanf("%d",&x)==1){
s += x;
if(x<min)
min = x;
if(x>max)
max = x;
n++;
}
cout<<min<<" "<<max<<" "<<s/(n*1.0);
return 0;
}
- 此时代码中添加了语句
#ifdef LOCAL
,意思是如果定义了#define LOCAL
就执行该语句,所以在比赛提交的时候删除define
语句采用标准输入输出即可,如果不删除的话cout
语句是不管用的。
6、不允许使用重定向方式读写数据时
那么在竞赛过程中,如果要使用文件读写,但是却不允许使用重定向的方式,又该如何?
- 使用
fin
和fout
,并把scanf
换成fscanf
,此时fscanf
第一个参数为fin
,把printf
换成fprintf
,此时fprintf
第一个参数为fout
,最后执行fclose
关闭fin、fout
。
代码如下:
#include<iostream>
using namespace std;
int main(){
const int INF = 10000000;
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;
}else if(x > max){
max = x;
}
n++;
}
fprintf(fout,"%d %d %.3f\n",min,max,(double)s/n);
fclose(fin);
fclose(fout);
return 0;
}
- 同样的,如果此时需要采用标准输入输出的话,可以将
fin = stdin
,fout = stdout
,并不调用fclose
和fopen
。
7、sprintf()函数
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main(){
char s[50];
int a,b,sum;
cin >> a >> b;
sum = a + b;
sprintf(s,"%d",sum);
return 0;
}
上例将sum变量转化成s,sum是整型,而s是字符类型,此时通过sprintf
函数将整型转换成字符类型,%d
是被转换的变量对应的类型。
- sprintf指的是字符串格式化命令,函数声明为
int sprintf(char *string, char *format [,argument,...])
,主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 string 所指向的字符串。 string--
这是指向一个字符数组的指针,该数组存储了 C 字符串。format--
这是字符串,包含了要被写入到字符串str
的文本。它可以包含嵌入的format
标签,format
标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format
标签属性是%[flags][width][.precision][length]specifier
[argument]...
:根据不同的format
字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了format
参数中指定的每个% 标签
。参数的个数应与% 标签
的个数相同。sprintf
是个变参函数。使用sprintf
对于写入buffer的字符数是没有限制的,这就存在了buffer溢出的可能性。解决这个问题,可以考虑使用sprintf
函数,该函数可对写入字符数做出限制。
8、程序的鲁棒性
- 算法竞赛中的题目的输入输出的是人设计的,难免会出错。比如题目指定输入以n=0为结束标记而真实数据忘记以n=0结尾的情形时,程序能自动处理好有瑕疵的数据,会节约大量不必要的时间浪费。
代码如下:
#include<iostream>
using namespace std;
int main(){
const int INF = 10000000;
int x, n, min = INF, max = -INF, s = 0, kase = 0;
while(scanf("%d",&n) == 1 && n){
s = 0;
min = INF, max = -INF;
for(int i=0;i<n;i++){
cin>>x;
s += x;
if(x < min){
min = x;
}else if(x > max){
max = x;
}
}
if(kase){
printf("\n");
}
printf("Case %d : %d %d %.3f\n",++kase, min, max, (double)s/n);
}
return 0;
}
此时,明明n
就可以判断程序读入的结束,为什么还要scanf("%d",&n) == 1
,就是考虑到上述问题。