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

题目链接:https://www.patest.cn/contests/pat-b-practise/1034


解题思路

  其实这道题思路很明确,但是牵涉细节比较多,想在短时间内A出来,也不容易,主要考察一些数学功底、逻辑缜密性和代码熟练度吧。

主要思路——
  1. scanf函数处理输入
  2. 进行加减乘除的计算
  3. 约分,辗转相除法
  4. 真分数化简,并化简为相应格式
  5. 按要求输出对应格式

一些细节——
  1.变量都要定义成长整型long,因为牵涉到乘法运算,使用int可能会造成溢出,提交报错“浮点错误”
  2.符号都是由分子来确定的,那么分母的运算可以用abs取正,这样判断每个分数的正负号可以仅通过分子以及运算过后的分子的正负号来确定,唯一需要特别注意的是除法运算,除数的分子分母是倒过来的。
  

AC的代码

#include
#include
using namespace std;

long a, b, c, d;

// 辗转相除法求解最大公约数,用于分子分母约分
long gcc(long x,long y){
    return y == 0 ? x : gcc(y, x%y);
}

void fraction(long numerator, long denominator){
    if (denominator == 0){
        cout << "Inf";
        return;
    }
    bool negative = false;
    long flag = 0;
    if (numerator < 0){
        negative = true;
        numerator = abs(numerator);
    }
    long temp = gcc(numerator, denominator);
    if (temp){
        numerator /= temp;
        denominator /= temp;
    }
    if (numerator>=denominator){
        flag = numerator / denominator;
        numerator %= denominator;
    }
    cout << (negative ? "(-" : "");
    if (flag != 0){
        cout << flag;
    }
    if (numerator != 0){
        cout << (flag?" ":"") << numerator << "/" << denominator;
    }
    else if (numerator == 0 && flag == 0){
        cout << 0 ;
    }
    cout << (negative ? ")" : "");
}

void addition(){
    long n = a*d + b*c;
    long m = abs(b*d);
    fraction(n, m);
}

void subtraction(){
    long n = a*d - b*c;
    long m = abs(b*d);
    fraction(n, m);
}

void multiplication(){
    long n = a*c;
    long m = abs(b*d);
    fraction(n, m);
}

void division(){
    long n = a*d;
    // 要注意除数分子的正负号,如果是符号,说明少乘了一次负号
    if (c < 0){
        n *= -1;
    }
    long m = abs(b*c);
    fraction(n, m);
}

void expression(string opt, void(*calculator)()){
    fraction(a, b);
    cout << opt;
    fraction(c, d);
    cout << " = ";
    calculator();
    cout << endl;
}

int main(){
    while (scanf("%ld/%ld %ld/%ld",&a,&b,&c,&d)!=EOF){
        // 加法
        expression(" + ", addition);
        // 减法
        expression(" - ", subtraction);
        // 乘法
        expression(" * ", multiplication);
        // 除法
        expression(" / ", division);
    }
    return 0;
}

参考链接

  
  1. 辗转相除法求最大公约数:https://baike.baidu.com/item/%E8%BE%97%E8%BD%AC%E7%9B%B8%E9%99%A4%E6%B3%95/4625352?fr=aladdin

你可能感兴趣的:(PAT-Basic,Level)