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;
}

过程资料

点评:
这道题目比较繁琐,涉及的点比较多,坑点也多,写起来比较蛋疼。


测试点:

  1. 第3、4个测试点用的是较大数字,如果仅仅用 int 整数的, 可能会导致预料外的错误,例如第4个测试点出现了浮点错误。解决方法是改为 long long。
作者:唐衣可俊
出处:http://www.cnblogs.com/tangyikejun/
版权:本文版权归作者本人所有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任