zoukankan      html  css  js  c++  java
  • 1054. 求平均值

    本题的基本要求非常简单:给定N个实数,计算它们的平均值。但复杂的是有些输入数据可能是非法的。一个“合法”的输入是[-1000,1000]区间内的实数,并且最多精确到小数点后2位。当你计算平均值的时候,不能把那些非法的数据算在内。

    输入格式:

    输入第一行给出正整数N(<=100)。随后一行给出N个正整数,数字间以一个空格分隔。

    输出格式:

    对每个非法输入,在一行中输出“ERROR: X is not a legal number”,其中X是输入。最后在一行中输出结果:“The average of K numbers is Y”,其中K是合法输入的个数,Y是它们的平均值,精确到小数点后2位。如果平均值无法计算,则用“Undefined”替换Y。如果K为1,则输出“The average of 1 number is Y”。
    输入样例1:

    7
    5 -3.2 aaa 9999 2.3.4 7.123 2.35
    

    输出样例1:

    ERROR: aaa is not a legal number
    ERROR: 9999 is not a legal number
    ERROR: 2.3.4 is not a legal number
    ERROR: 7.123 is not a legal number
    The average of 3 numbers is 1.38
    

    输入样例2:

    2
    aaa -9999
    

    输出样例2:

    ERROR: aaa is not a legal number
    ERROR: -9999 is not a legal number
    The average of 0 numbers is Undefined
    

    解体思路:

    吐槽:
    题目对 007000.01 这种数据居然都是接受的....
    题目对 12. 这种数据也是接受的...
    .9 也是接受的,不过测试点未包含这样的数据(本文的代码一不接受,代码二接受)
    像这种对输出格式要求很高的题目,应该描述得更加清晰才是。

    题目的格式控制说得很“宽泛”,实际上只有以下 3 点:

    • 除了符号外,只能包含数字和小数点;
    • 小数点只能有一位;
    • 小数点后最多有两位。

    本文包含两种解法:
    代码一未使用 atof 函数,手动实现了类似功能。
    代码二使用了 atof 函数。

    代码一:

    概述:
    首先,字符串有效长度大于 8 的舍去(最大为 -1000.00 这种情况)。然后将符号(正负)单独录入。之后就只剩下数字和小数点,非这两种类型的字符可以直接 Pass 掉,退出循环,输出当前字符串。输入的过程中注意控制小数点的个数,然后进行字符串转 double 型的处理

    具体细节:
    使用字符串来录入数据。题目中没有给定字符串长度,这里直接设定为 1000,如果提交不过,更改也很方便。

    首先判断第一位是否是 '+' 或者 '-',若是,指针指向下一位(j=1)。如果为负,则置 flag_negative 为 -1,最后 sum 值乘以它就转换成了负数。

    然后开始录入剩余的数字:

    • 非数字和小数点,标记为无效,然后退出。
    • 如果满足条件,开始转换字符串。这里使用的方法是,比如 123.45,先将 thisnum 计算至 12345,最后再除以 100 (由 dot 来统计),就可以得到其真正值。
    • 再注意小数点的情况。如果之前未遇到数字或者有两个小数点,则标记为无效。(之前一开始就把类似 21. 这种小数点在末尾的数字当作无效数据,导致测试点 4 一直通不过。)
    • 最后指针走到字符串末尾时,对 sum 和 count 进行统计。

    代码二:

    使用了 ctype.h 中的 isdigit 函数判断是否为数字字符,使用了 atof 函数将字符串转为 double 型数值。

    atof 函数省去了转换为数值的部分,只要先筛选出来既符合 atof 函数格式又是有效字符的格式就可以。先了解一下 atof 函数的参数格式:

    该函数包含在 <stdlib.h> 中。

    它可以将一个字符串转换为双精度的浮点数。

    输入一串具有特殊类型的字符串可以被解释为一个数值。该函数在遇到第一个无法作为数的一部分的字符时停止。这个字符也可能是字符串结束符。

    其参数格式为:

    [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
    
    • whitespace 可以是空格,可以是 Tab。
    • sign 可以是 '+' 或者 '-'。
    • digits 是一个或多个十进制字符。
    • 如果小数点前没有出现数字,那么在小数点之后至少要有一个数字。
    • 十进制数字中也可以包含一个指数,由一个引导字符 (d, D, e 或者 E) 加上一个可选的十进制数字构成。

    atof 函数更加宽容,比如输入 12.34ab,它会一直转换到自己不能转换的位置,所以它会输出 12.34

    根据题目的要求,在对字符串转换前做出以下筛选即可:

    • 除了符号外,只能包含数字和小数点;
    • 小数点只能有一位;
    • 小数点后最多有两位。

    解体代码:

    代码一:

    	#include<stdio.h> 
    	#include<string.h>
    	#define MAX 1000
    
    	int IsNumber (int i);
    
    	int main() 
    	{	 
    		int N;
    		scanf("%d", &N);
    		
    		double sum = 0;
    		int count = 0;
    		for (int i=0; i<N; i++) {
    			char s[MAX];
    			scanf("%s", &s);
    			int flag_negative = 1, invalid = 0;
    			int len = strlen(s), j = 0;
    			if (len <= 8) {
    				if (s[0] == '-' || s[0] == '+') {
    					if (s[0] == '-') flag_negative = -1;
    					if (s[0] == '+') flag_negative = 1;
    					j = 1;
    					if (len == 1) {
    						invalid = 1;
    					} // 只有一个负号或正号的情况 
    				} 
    				int dot_count = 0; // 小数点个数 
    				int thisnum = 0;
    				int dot = 1; // 用 1 10 100 这样的数来记录小数位数 
    				int flag = 0; // 标记遇到数字 
    				for (j; j<len; j++) {
    					if (!IsNumber(s[j]) && s[j]!='.') {
    						invalid = 1;
    						break;
    					} // 非数字 & 小数点,就退出 
    					if (IsNumber(s[j]) && dot_count<2) {
    						thisnum = thisnum * 10 + s[j] - '0';
    						if (dot_count) {
    							dot *= 10;
    							if (dot == 1000) {
    								invalid = 1;
    								break;
    							} // 小数点后有 3 位为无效 
    						}
    						flag = 1;
    					}
    					if (s[j] == '.') {
    						dot_count ++;
    						if (!flag || dot_count==2) {
    							invalid = 1;
    							break;
    						} // 之前没遇到数字/小数点有两个
    					}  
    					if (j == len-1) {  
    						double temp = (double)thisnum / (dot * flag_negative);
    						if (temp<=1000 && temp>=-1000) {	
    			           		count ++; 
    							sum += temp;
    						} else {
    							invalid = 1;
    						}
    					}
    				}			
    				if (invalid) {
    					printf("ERROR: %s is not a legal number
    ", s);
    				} 
    			} else {
    				printf("ERROR: %s is not a legal number
    ", s);
    			}
    		}
    		
    		if (count) {
    			if (count == 1) {
    				printf("The average of 1 number is %.2f
    ", sum/count);			
    			} else {
    				printf("The average of %d numbers is %.2f
    ", count, sum/count);
    			}
    		} else {
    			printf("The average of 0 numbers is Undefined
    ");
    		}
    		
    		return 0;
    	} 
    
    	int IsNumber (int i) {
    		if (i>='0' && i<='9') {
    			return 1;
    		} else {
    			return 0;
    		}
    	 } 
    

    代码二:

    #include<stdio.h> 
    #include<stdlib.h>
    #include<string.h>
    #include<ctype.h>
    #define MAX 1000
    
    int IsValid (char *s);
    
    int main() 
    {	 
    	int N;
    	scanf("%d", &N);
    	double sum = 0;
    	int count_valid = 0;
    	for (int i=0; i<N; i++) {
    		char s[MAX];
    		scanf("%s", &s);
    		if (IsValid(s)) {
    			double temp = atof(s);
    			if (temp>=-1000 && temp<=1000) {
    				sum += temp;
    				count_valid ++;
    			} else {
    				printf("ERROR: %s is not a legal number
    ", s);
    			}
    		} else {
    			printf("ERROR: %s is not a legal number
    ", s);
    		}
    	}
    	
    	if (count_valid) {
    		if (count_valid == 1) {
    			printf("The average of 1 number is %.2f
    ", sum/count_valid);			
    		} else {
    			printf("The average of %d numbers is %.2f
    ", count_valid, sum/count_valid);
    		}
    	} else {
    		printf("The average of 0 numbers is Undefined
    ");
    	}	
    	
    	return 0;
    } 
    
    int IsValid (char *s) {
    	int len = strlen(s); // 不要把 strlen 放在循环里,耗时(虽然不影响本题) 
    	int count_dot = 0; 
    	int after_dot = 0; // 统计小数点之后的数字 
    	if (len <= 8) {
    		for (int j=0; j<len; j++) {
    			if ((s[j]=='+' || s[j]=='-') && j==0) {
    				continue;
    			} // 跳过正负号 
    			if (!isdigit(s[j]) && s[j]!='.') {
    				return 0;
    			} // 非数字和小数点,返回 0 
    			if (count_dot) {
    				after_dot ++;
    				if (after_dot == 3) {
    					return 0;
    				} // 小数点后有 3 位,返回 0 
    			} 
    			if (s[j]=='.') {
    				count_dot ++; 
    				if (count_dot == 2) {
    					return 0;
    				} // 小数点等于 2 个时,返回 0 
    			} 
    		}
    		return 1;
    	} else {
    		return 0;
    	}
    }
  • 相关阅读:
    poj 2996 模拟
    poj 2965 BFS
    poj 1068 模拟
    poj 3295 前缀表达式求值
    常用的十七大学术搜索引擎
    Why,Unix or Linux ?
    匈牙利命名法
    微调控件(CSpinButtonCtrl)
    美国免费邮箱
    ASP常用的代码
  • 原文地址:https://www.cnblogs.com/andywenzhi/p/5848616.html
Copyright © 2011-2022 走看看