5-35 有理数均值
本题要求编写程序,计算N个有理数的平均值。
输入格式:
输入第一行给出正整数 N(≤ 100);第二行中按照a1/b1 a2/b2 …
的格式给出 N 个分数形式的有理数,其中分子和分母全是整形范围内的整数;如果是负数,则负号一定出现在最前面。
输出格式:
在一行中按照a/b
的格式输出N个有理数的平均值。注意必须是该有理数的最简分数形式,若分母为1,则只输出分子。
输入样例1:
4
1/2 1/6 3/6 -5/10
输出样例1:
1/6
输入样例2:
2
4/3 2/3
输出样例2:
1
解题思路:
先将各个分数通分。然后相加,乘以 1/N 之后再利用辗转相除法化简分数,得到最终值。
其中遇到的问题及思路整理:
之前的想法是将所有的分母累乘起来,然后再求公约数。结果后两例出现错误。思考原因应该是分母的累乘有可能会超过 int 型的表示范围。于是改成每两个分数就进行一次化简操作。这样两个分母的相乘的最大值应该是 int 型范围值最大值的平方。还是有可能超过 int 的表示范围。先提交测试测试,发现第 3 个用例依然错误。
有符号的 int 型表示范围上限为 2^31-1(这是 int 型占用 4 个字节时的情况,不同编译器可能有所差别),那么最大的那个值可能是 (231-1)2,难道要换成 double 型?double 型占用 8 个字节,正好满足它的范围。可是 double 型不能进行求余,也就意味着不能利用辗转相除法化简分母。其实 C99 还定义了一种长长整型,即 long long int 型,占用 8 个字节。也是刚好满足这个范围的。
解题代码:
#include<stdio.h>
struct fraction {
long long int numerator;
long long int denominator;
};
void add (struct fraction f[], int i, int j);
void reduction (struct fraction f[], int i);
int main ()
{
int N;
scanf ("%d", &N);
struct fraction f[N];
for (int i=0; i<N; i++) {
scanf ("%lld/%lld", &f[i].numerator, &f[i].denominator);
if (i >= 1) {
reduction (f, i); // 这里是通分之前的化简,可有可无的。
add (f, i-1, i);
reduction (f, i);
}
}
f[N-1].denominator *= N; //分母乘以 N 求平均数
reduction (f, N-1);
if (f[N-1].denominator == 1) {
printf ("%lld\n", f[N-1].numerator);
} else {
printf ("%lld/%lld\n", f[N-1].numerator, f[N-1].denominator);
}
return 0;
}
void reduction (struct fraction f[], int i) {
long long int a = f[i].numerator;
long long int b = f[i].denominator;
if (a < 0) a = -a; //最大公约数算法不能求负数
long long int temp;
while (b > 0) {
temp = a % b;
a = b;
b = temp;
}
f[i].numerator /= a;
f[i].denominator /= a;
} // 化简分数
void add (struct fraction f[], int i, int j) {
f[i].numerator *= f[j].denominator;
f[j].numerator *= f[i].denominator;
f[i].denominator *= f[j].denominator;
f[j].denominator = f[i].denominator;
f[j].numerator += f[i].numerator;
} // 通分并相加