3073: 【普及-】【P1572】计算分数

内存限制:128 MB 时间限制:1.000 S
评测方式:文本比较 命题人:
提交:1 解决:1

题目描述

Csh 被老妈关在家里做分数计算题,但显然他不愿意坐这么多复杂的计算。况且在家门口还有 Xxq 在等着他去一起看电影。为了尽快地能去陪 Xxq 看电影,他把剩下的计算题交给了你,你能帮他解决问题吗?


输入

输入一行,为一个分数计算式。

计算式中只包含数字、+-/。其中 / 为分数线,分数线左边为分子,右边为分母。输入数据保证不会出现繁分数。如果输入计算式的第一项为正,不会有前缀 + 号;若为负,会有前缀 - 号。

所有整数均以分数形式出现。

输出

输出一行,为最后的计算结果(用为整数则用整数表示,否则用最简分数表示)。

保证答案内出现的所有数(如果答案是分数即为分子和分母)均在 lns="http://www.w3.org/1998/Math/MathML">32 位带符号整数的表示范围之内。


样例输入 复制

2/1+1/3-1/4

样例输出 复制

25/12

提示

数据范围及约定

对于所有测试点,输入计算式长度在 lns="http://www.w3.org/1998/Math/MathML">100 以内,分子、分母在 lns="http://www.w3.org/1998/Math/MathML">1000 以内。同时保证,直接从前往后直接计算分数的和或者差,然后立刻化简,这么做的中间结果不会超过 int 的范围。

注意输入的分数不一定是最简分数。

#include <bits/stdc++.h>

using namespace std;
int a, b, c, d;

/**
 测试用例:
 2/1+1/3-1/4
 答案:25/12


 -2/1+1/3-1/4
 答案:-23/12

 测试点6
 7/4+1/3+8/5-3/2-6/9-6/4-5/2+6/2+4/9-3/9-2/3+5/2-5/4+3/9-3/8-5/8+6/8+3/8-4/7-5/7-3/6+6/9-5/6-5/7-5/2
 */
int gcd(int x, int y) {
    if (y == 0) return x;
    return gcd(y, x % y);
}

int lcm(int x, int y) {
    return x * y / gcd(x, y);
}

int main() {
    //和我一起念:scanf大法好!!
    scanf("%d/%d", &a, &b);

    //不断读取后面的数字,这玩意居然还能读入负号,牛!
    while (scanf("%d/%d", &c, &d) != EOF) {
        //通分,分母取最小公倍
        int e = lcm(b, d);
        //分子乘啊乘啊乘
        int f = e / b * a + e / d * c;
        //求最大公约数,约分
        int g = gcd(e, f);
        a = f / g;
        b = e / g;
    }
    if (gcd(a,b)!=1) {
    	int t=gcd(a,b);
    	a/=t;
    	b/=t;
	}
    
    //因为求负数最大公约,最小公倍也是可以的,但可能最终会出现1259/-360这样的情况
    //如果这时,需要特判一下,写成:-1259/360
    if (b < 0) a = -a, b = -b;

    //如果分母是1,就输出分子
    if (b == 1) printf("%d\n", a);
    else printf("%d/%d\n", a, b);
    return 0;
}