算法学习笔记-9-23

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、不允许使用重定向方式读写数据时

那么在竞赛过程中,如果要使用文件读写,但是却不允许使用重定向的方式,又该如何?

  • 使用finfout,并把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,并不调用fclosefopen

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,就是考虑到上述问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值