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;
} // 通分并相加
posted @ 2016-08-04 22:31  文之  阅读(802)  评论(0编辑  收藏  举报