PAT 1034 有理数四则运算(20)
题目
/*
1034. 有理数四则运算(20)
本题要求编写程序,计算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
*/
思路
// 1/2 + 4/5 =
// 如何把一个数化为最简分数?
// ::先化为真分数,再分子与分母的最大公约数
// 如何进行分数运算?
// ::分母通分(求最小公倍数),分子加成
代码
#include <iostream>
#include <stdio.h>
using namespace std;
long long maxCommon(long long a, long long b){
if(b == 0) return a;
else return maxCommon(b, a%b);
}
struct DivNum{
bool positive;
bool extInt;
bool extDiv;
long long int integer; //整数部分
long long int divChild;
long long int divMum;
bool isSimple;//是否已经化简
DivNum(){
positive = false;
extInt = false;
extDiv = false;
integer = 0;
divChild = 0;
divMum = 0;
isSimple = false;
}
void in(char * str){
string num = str;
if(str[0] == '-'){
num.erase(0,1);
}else{
positive = true;
}
sscanf(num.c_str(),"%lld/%lld", &divChild, &divMum);
}
void simplify(){
if(divMum == 0)return;
// 分子为0
if(divChild == 0) {
extInt = true;
extDiv = false;
integer = 0;
positive = true;
return;
}
extDiv = true;
// 假分数
if(divChild >= divMum){
extInt = true;
integer = divChild / divMum;
divChild = divChild % divMum;
//
if(divChild == 0) extDiv = false;
}
// 化为最简真分数
long long common = maxCommon(divChild, divMum);
if(common == 0) return;
divChild /= common;
divMum /= common;
}
friend DivNum operator +(const DivNum &a, const DivNum &b){
DivNum res;
// 一正一副,相加==相减,结果为符号
// 正正或者负负,符号不变,
if(!a.positive == b.positive){
res.divChild = a.divChild*b.divMum - b.divChild*a.divMum;
res.positive = res.divChild < 0 ? !a.positive:a.positive; // 正+负-》得负,符号为负,负+正-》得负,符号为正
if(res.divChild < 0) res.divChild = -res.divChild;
if(res.divChild == 0) res.positive = true;
}else{
res.positive = a.positive;
res.divChild = a.divChild*b.divMum + b.divChild*a.divMum;
}
res.divMum = a.divMum * b.divMum;
return res;
}
void reversePositive(){positive = !positive;}
friend DivNum operator -(DivNum const &a, DivNum const &b){
// a-b = a + (-b)
DivNum c = b;
c.reversePositive();
return a + c;
}
friend DivNum operator *(const DivNum &a,const DivNum &b){
DivNum res;
res.positive = (a.positive && b.positive)||(!a.positive && !b.positive); // 正正得正,负负得正
res.divChild = a.divChild * b.divChild;
res.divMum = a.divMum * b.divMum;
if(res.divChild == 0) res.positive = true;
return res;
}
friend DivNum operator /(const DivNum &a, const DivNum &b){
DivNum res;
res.positive = (a.positive && b.positive)||(!a.positive && !b.positive); // 正正得正,负负得正
res.divChild = a.divChild * b.divMum;
res.divMum = a.divMum * b.divChild;
if(res.divChild == 0) res.positive = true;
return res;
}
void out(){
if(!isSimple){
simplify();
isSimple =true;
}
if(divMum){ // 分母不为0
if(!positive) cout << "(-";
if(extInt) cout << integer;
if(extInt && extDiv) cout << " ";
if(extDiv) cout << divChild << "/" << divMum;
if(!positive) cout << ")";
}else{
cout << "Inf";
}
}
};
int main(){
// 得到两个数字
char str1[30],str2[30];
scanf("%s%s",str1,str2);
DivNum a,b;
a.in(str1);
b.in(str2);
DivNum res[4];
char op[4]={'+','-','*','/'};
res[0] = a+b;
res[1] = a-b;
res[2] = a*b;
res[3] = a/b;
for (int i = 0; i < 4; ++i) {
a.out();cout << " " << op[i] << " ";b.out();cout << " = ";res[i].out();cout << endl;
}
// 化为最简分数保存起来
// 进行四则运算得到四个结果
// 输出
return 0;
}
过程资料
点评:
这道题目比较繁琐,涉及的点比较多,坑点也多,写起来比较蛋疼。
测试点:
- 第3、4个测试点用的是较大数字,如果仅仅用 int 整数的, 可能会导致预料外的错误,例如第4个测试点出现了浮点错误。解决方法是改为 long long。