// 正确代码
#include <bits/stdc++.h>
using namespace std;
int main() {
// N个实数 剔除非法数据 求平均值
int n, legal = 0;
double result = 0, num = 0;
cin >> n;
while(n--) {
char a[100], b[100];
scanf("%s", &a);
sscanf(a, "%lf", &num);
sprintf(b, "%.2f", num);
int flag = 0;
for(int j = 0; j < strlen(a); j++)
if(a[j] != b[j]) flag = 1;
// 非数字判断 或 区间判断
if(flag || abs(num) > 1000)
printf("ERROR: %s is not a legal number\n", a);
// 合法统计
else
result += num, legal++;
}
// 结果保留两位小数
if(legal == 0)
printf("The average of 0 numbers is Undefined");
else if(legal == 1)
printf("The average of 1 number is %.2f", result);
else
printf("The average of %d numbers is %.2f", legal, result / legal);
}
// 15分代码
#include <bits/stdc++.h>
using namespace std;
// 判断两位小数
bool two(string str){
int point = false, cnt = 0;
for(auto s : str){
if(s == '.'){
point = true;
// 跳过当前小数点. 防止多统计一次
continue;
}
// 有小数点后开始统计
if(point == true) ++cnt;
if(cnt > 2) return true;
}
return false;
}
bool alpha(string str){
int cnt = 0;
for(auto s : str){
if(isalpha(s)) ++cnt;
if(cnt > 0) return true;
}
return false;
}
int main() {
// N个实数 剔除非法数据 求平均值
int n, legal = 0;
double result = 0;
cin >> n;
while(n--){
string str;
cin >> str;
// 非数字判断 或 区间判断
if(alpha(str) || count(begin(str), end(str), '.') > 1 ||
two(str) || abs(stoi(str)) > 1000)
printf("ERROR: %s is not a legal number\n", str.c_str());
// 合法统计
else
result += atof(str.c_str()), legal++;
}
// 结果保留两位小数
if(legal == 0)
printf("The average of 0 numbers is Undefined");
else
printf("The average of %d numbers is %.2f", legal, result / legal);
}
其实感觉不需要自己额外判断,如果可以捕获错误的话,用try-catah打印错误信息即可。不过试了下不晓得c++要怎么写,好像atof不会抛出异常。
试了试,原来c++的cin会自动截取正确数据,而不会认为输入的这一串东西应该属于一个类型。所以就没有抛出异常。atof应该也是同理。
看别人的代码用到了 sscanf 和 sprintf 跟原来的输入输出区别仅在于前面多了一个 s ,应该跟字符串 string 关系的缘故。
sscanf 是将字符串以格式化输出到其他变量,就像 scanf 区别只是将标准化输入设备 stdin 换成了 string 字符串作为输入。sscanf 跟 scanf 一样不要忘了加 & 取地址。
sprintf 同理,将本来输出 stdout 变成了字符串。
scanf("%s", a);
别人代码处,因为 a 作为字符串数组变量名本身就是地址了,所以就不需要加 & 。 字符串和其他类型的数组应该具有相似的原理。
然后看下别人这部分代码是怎么工作的。
首先是输入正确数据的话,a 里面会得到一个 5,而 5 通过 %.2f 传给 b 就会变成浮点类型,多出小数点和后面的 0 。但后面有判断语句,条件是根据 a 的长度比较转换成 b 之后其中的字符是否一致。虽然长度上 b > a , 但只判断到 a 的 5就停止了,后面多出来的没关系,也算正确。这是整型时情况。
如果是正确的浮点和整型类似,只是 a 也会有小数点后面的数据。
如果输入乱七八糟的情况,比如全部非数字的,或者前面数字后面非数字的,可以看到测试结果的处理方式跟前面,cin 输入如果遇到非对应数据类型的处理方式相似,只会将正确的部分读取,而其他抛弃。
比如上面的图,全部是字母情况,那么一个正确的 double 类型的数据都没有,所以只能够得到一个 0.00 的结果。而下面的情况,就将前面正确的数截取,后面的全部抛弃,比如 5 就留下来变成了 5.00 后面从 a 开始的部分就没有了,即便里面可能有数字。
多余小数点的处理思路类似,一个小数点是合法浮点数,再多就非法,所以多余小数点及其后面部分就被抛弃了。
而如果是超过合法的两位小数位,那么在判断时候,会判断两个字符串不同位置是否一致,显然 a 后面还有许多数字,跟合法的 b 就不相同,就会返回 false。
当时自己写是差 2 3 测试点未通过,想了想虽然参考别人的解题方法能够全部AC,也知道别人的处理的方法,但是自己应该怎样调整还是很困难的,或者说自己原来缺陷的部分应该怎样改进,光靠别人正确的代码还是很困难的。
刚才查阅的时候还试了试字符数组和字符串之间的转化,如果是字符数组转成字符串的话,直接等号赋值即可, str = a; 这样。
如果是字符串赋值给字符数组,则需要借助一个函数 strcpy() C语言里面,同时将字符串转化成字符数组用 c_str() 函数 变成 strcpy(a, str.c_str()); 。
当时只知道一个字符串转换成数字的函数 stoi(),以为这个东西能够变成浮点数,结果测试只能够变成整型。而变成浮点数得借助另一个函数 atof() 。
这题还有一个要注意的,就是输出的时候字符串里面有一个单词 number 复数的时候是会 + s 的 numbers 如果是一个结果就是 number 。
也就说以后输出的时候不仅要考虑数据上面的边界问题,还得注意下输出的东西是否符合英文的语法。。
所以查了查,发现还是有很多人研究不同测试点的特殊情况是什么的。我们可以借助这些对应的文章来改进原来考虑的不足,这比单纯学习别人全部AC的方法要更好点。
不然真正写的时候,光有方法但对于特殊情况没有意识,即便知道方法也不知道应该用怎样的方式来处理。