PAT 乙级 1034 有理数四则运算

题目

本题要求编写程序,计算 2 个有理数的和、差、积、商。
输入格式:
输入在一行中按照 a1/b1 a2/b2 的格式给出两个分数形式的有理数,其中分子和分母全是整型范围内的整数,负号只可能出现在分子前,分母不为 0。
输出格式:
分别在 4 行中按照 有理数1 运算符 有理数2 = 结果 的格式顺序输出 2 个有理数的和、差、积、商。注意输出的每个有理数必须是该有理数的最简形式 k a/b,其中 k 是整数部分,a/b 是最简分数部分;若为负数,则须加括号;若除法分母为 0,则输出 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

分析

模拟 + 代码化
这道题真是到巨坑的题,第二个测试点找了我一天!

AC代码

//模拟 + 代码化

/*
分母为零加减法不能过
公约数为零乘除法不能过
float point expection -> 不能除0
mle or segmentation fault -> gcd传参不能一正一负,正数和负数是没有最大公因数的,同号之间才有最大公约数 -> gcd 传参是一定要都是正整数
不要用int,用ll,两个int相乘时可能爆longlong

测试样例
1.
-0/7 7/3
2.
0/5 0/8  除法爆
3.
12/10 15/12  第二个测试点
输入的两个数也要约分约彻底
错误输出:
12/10 15/12
1 2/10 + 1 3/12 = 2 9/20
1 2/10 - 1 3/12 = (-1/20)
1 2/10 * 1 3/12 = 1 1/2
1 2/10 / 1 3/12 = 24/25

正确输出
1 1/5 + 1 1/4 = 2 9/20
1 1/5 - 1 1/4 = (-1/20)
1 1/5 * 1 1/4 = 1 1/2
1 1/5 / 1 1/4 = 24/25
*/

/*
0 对任何数取模都等于 0

任意整数和0的公约数是该整数的所有约数
它们的最大公约数为该整数本身
因为0被所有非0整数整除,所以任意非零的整数都是0的约数

0与0的最大公约数是0
*/

#include <iostream>
#include <cmath>

using namespace std;

typedef long long ll;

string a, b;
ll a1, a2, b1, b2, fz, fm;

/*
若gcd传参是一正一负模拟程序
5 -3
-3 2 ->2 -3
-3 2 ->2 -3
-3 2
... 死循环

** 一个整数a,一个整数b
** if abs(a) < abs(b) -> a % b = a;
*/
inline ll gcd (ll a, ll b)
{
    if(b > a) return gcd(b, a);
    
    return b == 0 ? a : gcd(b,a % b);
}

inline ll lcm (ll a, ll b)
{
    return a * b / gcd(a, b);
}

inline void out (char c)
{
    if(a1 < 0) printf("(");
    
    if(a1 == 0) printf("0");
    else if(abs(a1) < abs(a2)) printf("%lld/%lld", a1, a2);
    else if(a1 % a2 == 0)  printf("%lld", a1 / a2);
    else if(a1 % a2 != 0) printf("%lld %lld/%lld", a1 / a2, abs(a1) % a2, a2);
    
    if(a1 < 0) printf(")");
    
    printf(" %c ", c);
    
    if(b1 < 0) printf("(");
    
    if(b1 == 0) printf("0");
    else if(abs(b1) < abs(b2)) printf("%lld/%lld", b1, b2);
    else if(b1 % b2 == 0)  printf("%lld", b1 / b2);
    else if(b1 % b2 != 0) printf("%lld %lld/%lld", b1 / b2, abs(b1) % b2, b2);
    
    if(b1 < 0) printf(")");
    
    printf(" = ");
    
    if(fz < 0) printf("(");
    
    if(fz == 0) printf("0"); //0/8 15/4
    else if(fm == 0) printf("Inf"); //5/3 0/6
    else if(abs(fz) < abs(fm)) printf("%lld/%lld", fz, fm);  //3/4
    else if(fz % fm == 0)  printf("%lld", fz / fm); //-4 2
    else if(fz % fm != 0) printf("%lld %lld/%lld", fz / fm, abs(fz) % fm, fm); //-5 3 
    
    if(fz < 0) printf(")");
    
    printf("\n");
}

inline void add ()
{
    ll gbs = lcm(a2, b2);
    
    ll gys = gcd(abs((gbs / a2) * a1 + (gbs / b2) * b1), gbs);
    
    fz = ((gbs / a2) * a1 + (gbs / b2) * b1) / gys;
    fm = gbs / gys;
    
    out('+');
}

inline void sub ()
{ 
    ll gbs = lcm(a2, b2);
    
    ll gys = gcd(abs((gbs / a2) * a1 - (gbs / b2) * b1), gbs); //一个正数和一个负数没有公约数
    
    fz = ((gbs / a2) * a1 - (gbs / b2) * b1) / gys;
    fm = gbs / gys;
    
    out('-');
}

inline void mul ()
{
    fz = a1 * b1;
    fm = a2 * b2;
    
    ll gys = gcd(abs(fz), abs(fm));
    fz = fz / gys;
    fm = fm / gys;
    
    out('*');
}

inline void div ()
{   
	fz = a1 * b2;
	fm = a2 * b1;
	//cout<<fz<<" "<<fm<<" "<<endl;
	if(fz == 0 && fm == 0) //0/8 0/9
	{
	printf("0 / 0 = Inf\n");
	return ;
	}
	
	ll gys = gcd(abs(fz), abs(fm));
	fz /= gys;
	fm /= gys;
	
	if(fm < 0) {fm = -fm; fz = -fz;}
	
	out('/');
}

int main ()
{
	//***
	scanf("%lld/%lld %lld/%lld", &a1, &a2, &b1, &b2); 
	
	//输入的分数也要约分输出 测试点2 
	ll gys_a = gcd(abs(a1), abs(a2));
	a1 /= gys_a;
	a2 /= gys_a;
	ll gys_b = gcd(abs(b1), abs(b2));
	b1 /= gys_b;
	b2 /= gys_b;
	
	add();
	sub();
	mul();
	div();
	
	return 0;
}	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值