1088 Rational Arithmetic (20分) 思路分析 测试点分析(解决你的测试点过不了)

题目

For two rational numbers, your task is to implement the basic arithmetics, that is, to calculate their sum, difference, product and quotient.
Input Specification:

Each input file contains one test case, which gives in one line the two rational numbers in the format a1/b1 a2/b2. The numerators and the denominators are all in the range of long int. If there is a negative sign, it must appear only in front of the numerator. The denominators are guaranteed to be non-zero numbers.
Output Specification:

For each test case, print in 4 lines the sum, difference, product and quotient of the two rational numbers, respectively. The format of each line is number1 operator number2 = result. Notice that all the rational numbers must be in their simplest form k a/b, where k is the integer part, and a/b is the simplest fraction part. If the number is negative, it must be included in a pair of parentheses. If the denominator in the division is zero, output Inf as the result. It is guaranteed that all the output integers are in the range of long int.
Sample Input 1:

2/3 -4/2

Sample Output 1:

2/3 + (-2) = (-1 1/3)
2/3 - (-2) = 2 2/3
2/3 * (-2) = (-1 1/3)
2/3 / (-2) = (-1/3)

Sample Input 2:

5/3 0/6

Sample Output 2:

1 2/3 + 0 = 1 2/3
1 2/3 - 0 = 1 2/3
1 2/3 * 0 = 0
1 2/3 / 0 = Inf

题目大意

对于两个有理数,你的任务是实现基本算法,即计算它们的和、差、积和商。
输入规格:

每个输入文件包含一个测试用例,在一行中给出两个格式为a1/b1 a2/b2的有理数。分子和分母都在长整数的范围内。如果有负号,它只能出现在分子前面。分母保证为非零数字。
输出规格:

对于每个测试用例,分别用4行打印两个有理数的和、差、积和商。每行的格式是数字1运算符数字2 =结果。请注意,所有有理数都必须是最简单的k a/b形式,其中k是整数部分,a/b是最简单的分数部分。如果数字是负数,它必须包含在一对括号中。如果除法中的分母为零,则输出Inf作为结果。保证所有的输出整数都在长整型的范围内。
样本输入1:

2/3 -4/2

样本输出1:

2/3 + (-2) = (-1 1/3)
2/3 - (-2) = 2 2/3
2/3 *(2)= 1 1/3
2/3/(-2)= 1/3

样本输入2:

5/3 0/6

样本输出2:

1 2/3 + 0 = 1 2/3
1 2/3 - 0 = 1 2/3
1 2/3 * 0 = 0
1 2/3 / 0 = Inf

思路分析

这道题是1081的数据延伸,1081实现的是加法,这里实现的是四则运算。如果这道题写着很吃力,可以先去写1081,打个基础。这里提供两种思路:

思路1

这道题的任务是实现有理数的四则运算,那么我们可以将四则运算的加减乘除分别用函数封装实现。(这里的情况比较复杂,所以封装函数,不然全部写到main函数里面会特别得乱)。这一种思路相对来说复杂一些。

思路2

这道题的关键在于几个函数:
gcd函数和化简函数,只要写好了这几个函数,这道题也就解决了。对于其中的四则运算,可以直接在化简函数中进行运算即可。

测试点分析

(1) 化简,采用辗转相除法,也就是gcd函数。包括加减乘除的结果也要化简。
(2) 格式化输出,负数要加括号。此处我输出采用的字符串,我觉得比数字输出简单一些。
(3)防止数据溢出。
这道题只要你把标准测试案例通过了,差不多就能拿14分,难点是在于测试点2,3;
最开始我去网上搜测试点,大部分说测试点3因为相乘导致数据溢出,后来我改出来之后发现并不是这样。
我从自己想,和从牛客网套了一些测试点,如下:
4/8 4/8
1/-6 1/5
0/3 0/2
1/3 2/10
我把这些测试点过了之后,这道题也就跑满了。

代码

代码1(代码量较大)

#include<iostream>
using namespace std;
struct node
{
	long long up;
	long long down;
	bool symbol;
}a, b;
long long gcd(long long a, long long b)
{
	return b == 0 ? abs(a) : gcd(b, a%b);
}
node reduction(node a)
{
	long long gcdvalue = gcd(abs(a.up), abs(a.down));
	if (gcdvalue)
	{
		a.up = a.up / gcdvalue;
		a.down = a.down / gcdvalue;
	}
	return a;
}
node add(node a, node b)
{
	a.up = a.up*b.down + b.up*a.down;
	a.down = a.down*b.down;
	if (a.up*a.down<0) a.symbol = false;
	else a.symbol = true;
	return reduction(a);
}
node sub(node a, node b)
{
	a.up = a.up*b.down - b.up*a.down;
	a.down = a.down*b.down;
	if (a.up*a.down < 0) a.symbol = false;
	else a.symbol = true;
	return reduction(a);
}
node multi(node a, node b)
{
	a.up = a.up*b.up;
	a.down = a.down*b.down;
	if (a.up*a.down < 0) a.symbol = false;
	else a.symbol = true;
	return reduction(a);
}
node div(node a, node b)
{
	a.up = a.up*b.down;
	a.down = a.down*b.up;
	if (a.up*a.down < 0) a.symbol = false;
	else a.symbol = true;
	return reduction(a);
}
void show(node a)
{
	if (a.symbol == false)
	{
		printf("(");
		a.up = -1 * abs(a.up);
		a.down = abs(a.down);
	}
	else
	{
		a.up = abs(a.up);
		a.down = abs(a.down);
	}
	if (a.up%a.down == 0) printf("%lld", a.up / a.down);
	else if (abs(a.up) > abs(a.down)) printf("%lld %lld/%lld", a.up / a.down, abs(a.up%a.down), a.down);
	else
	{
		printf("%lld/%lld", a.up, abs(a.down));
	}
	if (a.symbol == false) printf(")");
}
int main()
{
	scanf("%lld/%lld %lld/%lld", &a.up, &a.down, &b.up, &b.down);
	if (a.up*a.down < 0) a.symbol = false;
	else a.symbol = true;
	if (b.up*b.down < 0) b.symbol = false;
	else b.symbol = true;
	a=reduction(a);
	b=reduction(b);
	show(a);
	printf(" + ");
	show(b);
	printf(" = ");
	show(add(a, b));
	printf("\n");
	show(a);
	printf(" - ");
	show(b);
	printf(" = ");
	show(reduction(sub(a, b)));
	printf("\n");
	show(a);
	printf(" * ");
	show(b);
	printf(" = ");
	show(reduction(multi(a, b)));
	printf("\n");
	show(a);
	printf(" / ");
	show(b);
	printf(" = ");
	if (div(a, b).down == 0) printf("Inf\n");
	else
	{
		show(reduction(div(a, b)));
		printf("\n");
	}
	return 0;
}

代码2

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
long long gcd(long a, long b)
{
	return b == 0 ? abs(a) : gcd(b, a%b);
}
string deduction(long long up1, long long down1)
{
	string s;
	int flag = 0;
	long long gcdvalue = gcd(abs(up1), abs(down1));
	if (up1 == 0)
	{
		s = "0";
		return s;
	}
	if (gcdvalue)
	{
		up1 /= gcdvalue;
		down1 /= gcdvalue;
	}
	if ((up1>0&&down1 < 0)||(up1<0&&down1>0))
	{
		up1 = (-1)*(abs(up1));
		down1 = abs(down1);
		s += '(';
		s += '-';
		flag = 1;
	}
	if (abs(up1) % abs(down1) == 0)
	{
		string t;
		up1 = abs(up1);
		down1 = abs(down1);
		s += to_string(abs(up1) / abs(down1));
	}
	else if (abs(up1) < abs(down1))
	{
		s += to_string(abs(up1));
		s += '/';
		s += to_string(abs(down1));
	}
	else
	{
		s+=to_string(abs(up1 / down1));
		s += ' ';
		s += to_string(abs(up1) % down1);
		s += '/';
		s += to_string(down1);
	}
	if(flag==1) s += ')';
	return s;
}
int main()
{
	long long up1, down1, up2, down2;
	scanf("%lld/%lld %lld/%lld", &up1, &down1, &up2, &down2);
	cout << deduction(up1, down1) << " + " << deduction(up2, down2) << " = " << deduction(up1*down2 + up2 * down1, down1*down2) << endl;
	cout << deduction(up1, down1) << " - " << deduction(up2, down2) << " = " << deduction(up1*down2 - up2 * down1, down1*down2) << endl;
	cout << deduction(up1, down1) << " * " << deduction(up2, down2) << " = " << deduction(up1*up2, down1*down2) << endl;
	cout << deduction(up1, down1) << " / " << deduction(up2, down2) << " = ";
	if(up2!=0&&down2!=0) cout<<deduction(up1*down2, down1*up2) << endl;
	else cout << "Inf" << endl;
	return 0;
}

总结

这道题我从11点写到2点半,把两种方法写了出来,但是代码不够简洁,有待改进。测试点2,3确实很磨人!

©️2020 CSDN 皮肤主题: 游动-白 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值