【题目描述】
输入一些整数,求出它们的最小值、最大值和平均值(保留3位小数)。输入保证这些数都是不超过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.375
Case 2: -4 10 3.000
【题目来源】
刘汝佳《算法竞赛入门经典 第2版》例题2-6 数据统计II
【解析】
本题涉及输入多组数据,直接上书中代码:
#include<stdio.h>
#define INF 1000000000
int main(){
int x, n = 0, min = INF, max = -INF, s = 0, kase = 0;
while(scanf("%d", &n) == 1 && n){
int min = INF, max = -INF, s = 0;
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;
}
这段代码有几个原书指出的要点:
(1)程序健壮性:虽然题目指明n=0为输入结束标记,但有时题目设计也会出错,真实数据可能忘记以n=0结尾。为了防止这种情况带来不必要的丢分,最好的方法就是在代码中增加一道保险,使其不输入0也能正常结束输入,这时就又会用到scanf("%d", &n) == 1来进行输入结束判断(原理详见《非常绕的“输入结束”信号》一文)。这种增加保险的代码在计算机中称之为“鲁棒性(robustness)”。
这里老金不得不吐槽两句,去**的“鲁棒性”!这是一个典型的把简单问题复杂化,莫名其妙装叉,看似高深莫测实则不伦不类的词。因为“鲁棒性”纯粹是个音译词。也不是说音译词就不好,在没有合适的中文表达情形下也无可厚诽。关键是,robustness明明有那么明确又通俗易懂的汉语意思“健壮性”,你却偏偏搞出这个生僻的音译飞机,这不是明显的装叉大以巴狼嘛!
更有甚者,有人还强行从汉字字义加以解释,老金搬来权当一乐。
逻辑是这样的:
总结起来就是:
不得不说,这个总结还真有创意,但咱们又不是在搞古文运动。况且,这种组合词本身意思也不明朗,我也可以解释成“鲁莽的人很棒”、“粗鲁的人很棒”、愚鲁的人很棒”,甚至可以解释成“鲁讯很棒”。所以,即便能像前面高人这样强行解释,对于大众来说,它也绝对不是一个好词。它就是不够简明,不够通俗易懂。任何一个人第一次面对它,都会莫名其妙。随便用“健壮性”、“容错性”、“可靠性”,哪怕是“抗造性”,最不济用“程序猛男”也比这个词更容易理解。
此外,老金真心觉得上面的字意引申过程不够平滑,特意查了字典,重新梳理下逻辑。
鲁:象形字,上鱼下口→鱼入口中→吃到了美味佳肴→美好。上面是字典中能查到的,
然后在前人的启发下进一步开启老金脑补模式:美好的东西自然要多多益善→东西一多总体积就会变“大”→大的东西就“粗”→粗大的东西就不灵活,就比较“愚钝”,于是有了“愚鲁”→“愚鲁”的人往往比较“粗俗”,于是有了“粗鲁”、“鲁莽”。
(2)输出格式:程序要求“相邻两组数据之间应输出一个空行”。要准确理解这句话的意思,即第一行前不能有空行,最后一行后不能有空行。if(kase) printf("\n");就是为了实现这个功能。这里尤其要说明的一点,虽然最后的printf语句中也有\n,但它只是换行,即把光标移到下一行,但不代表下一行就是空行。所以,最后一组数据输出后是不会输出空行的。
(3)变量重置:这是一个易错点。因为本题涉及“多组数据”输入。因此,为了避免上一组数据运算过后变量的值对下一组数据运算的结果产生影响,需要在进行每一组数据运算前都要对参与运算的变量进行重新初始化。题中对运算结果有影响的变量有4个:x、min、max、s。它们都应在while循环内每次运算前进行初始化。x是由用户输入的值进行初始化的,不会有问题。关键是min、max、s这3个变量,很容易放在while之外。要说明的是,像代码中那样里外都进行变量定义和初始化也是可以的,因为内层的变量会屏蔽外层的同名变量,只不过外层的那些都是多此一举。
除以上要点之外,老金还有必要提出一点,就是代码运行后的输入和输出是交叉出现在画面中的,即像下面这样。
这貌似很混乱,与题目输入、输出要求相悖,实际上是没问题的,因为输入和输出天然就是是分开的,咱们只要保证分别从输入、输出两方面看与题目要求相符即可,不用因此担心丢分。
如果非要使输出结果中的输入、输出区分开来也是可以的,就要用到二维组,用来存储每次运算后的输出结果。
假设最多输入100组数据,代码如下:
#include<stdio.h>
#define INF 1000000000
int main(){
int x, n = 0, min = INF, max = -INF, s = 0, kase = 0, a[100][2];
double b[100][1];
while(scanf("%d", &n) == 1 && n){
int min = INF, max = -INF, s = 0;
for(int i = 0; i < n; i++) {
scanf("%d", &x);
s += x;
if(x < min) min = x;
if(x > max) max = x;
}
a[kase][0] = min;
a[kase][1] = max;
b[kase][0] = (double)s/n;
kase++;
}
for(int i=0; i<kase; i++){
if(i) printf("\n");
printf("Case %d: %d %d %.3f\n", i+1, a[i][0], a[i][1], b[i][0]);
}
return 0;
}
输出结果: