计算机中采用浮点数表示所有实数,但这意味着精度丢失。例如无法精确表示“1/3”。
NowCoder最近要处理很多金融问题,这些账目不允许出现精度丢失,因为差之毫厘谬之千里。你能帮他实现一套分数的计算器吗?
输入包含多组数据。
每组数据一行,包含两个分数和一个运算符,中间用空格隔开。
其中分子与分母均为不大于30的正整数。
对应每一组数据,输出两个分数的计算结果。
要求输出最简分数,即分子与分母互质。
1/3 2/3 +<br/>1/5 1/4 -<br/>1/2 1/3 *<br/>2/3 4/3 /
1/1<br/>-1/20<br/>1/6<br/>1/2
#include<stdio.h> int gcd(int x, int y) { if (y%x == 0) return x; return gcd(y%x, x); } int main() { int nom1, nom2, den1, den2, den, newNom1, newNom2, tmpNom, tmpDen, tmpGcd, resNom, resDen; char op; while (~scanf("%d/%d%d/%d %c", &nom1, &den1,&nom2,&den2,&op)) { den = den1*den2 / gcd(den1, den2); newNom1 = nom1*den / den1; newNom2 = nom2*den / den2; switch (op) { case '+': tmpNom = newNom1 + newNom2; tmpDen = den; break; case '-': tmpNom = newNom1 - newNom2; tmpDen = den; break; case '*': tmpNom = nom1*nom2; tmpDen = den1*den2; break; case '/': tmpNom = nom1*den2; tmpDen = den1*nom2; break; } tmpGcd = gcd(tmpNom, tmpDen); resNom = tmpNom / tmpGcd; resDen = tmpDen / tmpGcd; resNom = resNom*resDen < 0 ? -abs(resNom) : abs(resNom); resDen = abs(resDen); printf("%d/%d\n",resNom,resDen); } return 0; }
实现思路:
1、构造分数类;
2、实现四则运算;
3、利用 “辗转相除法 ”思想构造求最大公约数的算法;
4、利用最大公约数进行月份简化;
5、输出;
另外需要注意的是,尽量减少分数简化(约分)次数,我之前几次超时,原因是构造分数时就进行一次约分。实际上只需要在 输出前 约分 就行;
以下代码仅供参考:
import java.util.Scanner;
/**
* @author MemoryC
* */
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
while(scanner.hasNext()) {
String[]aStrings=scanner.next().split("/");
String[] bString=scanner.next().split("/");
char operation=scanner.next().charAt(0);
Fraction a=new Fraction(Integer.parseInt(aStrings[0]), Integer.parseInt(aStrings[1]));
Fraction b=new Fraction(Integer.parseInt(bString[0]), Integer.parseInt(bString[1]));
Fraction c=null;
switch (operation) {
case '+':
c=Fraction.add(a, b);
break;
case '-':
c=Fraction.cut(a, b);
break;
case '*':
c=Fraction.multiply(a, b);
break;
case '/':
c=Fraction.divide(a, b);
break;
default:
break;
}
c.Simplify();
System.out.println(c);
}
scanner.close();
}
static class Fraction{
int mom=1;
int son=0;
boolean negtive=false;
public Fraction(int son,int mom) {
if(son<0) {
son=-son;
negtive=true;
}else if(son==0) {
mom=1;
}
this.son=son;
this.mom=mom;
}
public String toString() {
return negtive?("-"+son+"/"+mom):(son+"/"+mom);
}
static int getCommonDivisor(int a,int b) {
if(a<b) {
return getCommonDivisor(b,a);
}
int aa=a;
int bb=b;
while(aa%bb!=0) {
int r=aa%bb;
aa=bb;
bb=r;
}
return bb;
}
void Simplify() {
if(son==mom) {
son=1;
mom=1;
}else {
int common=getCommonDivisor(son, mom);
son=son/common;
mom=mom/common;
}
}
static Fraction add(Fraction a,Fraction b) {
int am=a.mom,as=a.son,
bm=b.mom,bs=b.son,
cm=0,cs=1;
if(a.negtive) {
as=-as;
}
if(b.negtive) {
bs=-bs;
}
cm=am*bm;
cs=as*bm+bs*am;
return new Fraction(cs,cm);
}
static Fraction cut(Fraction a,Fraction b) {
int am=a.mom,as=a.son,
bm=b.mom,bs=-b.son,
cm=0,cs=1;
if(a.negtive) {
as=-as;
}
if(b.negtive) {
bs=-bs;
}
cm=am*bm;
cs=as*bm+bs*am;
return new Fraction(cs,cm);
}
static Fraction multiply(Fraction a,Fraction b) {
int am=a.mom,as=a.son,
bm=b.mom,bs=b.son,
cm=0,cs=1;
if(a.negtive) {
as=-as;
}
if(b.negtive) {
bs=-bs;
}
cm=am*bm;
cs=as*bs;
return new Fraction(cs,cm);
}
static Fraction divide(Fraction a,Fraction b) {
int am=a.mom,as=a.son,
bm=b.son,bs=b.mom,
cm=0,cs=1;
if(a.negtive) {
as=-as;
}
if(b.negtive) {
bs=-bs;
}
cm=am*bm;
cs=as*bs;
return new Fraction(cs,cm);
}
}
}
#include <stdio.h> int gcd(int x,int y) //求最大公约数 { if(y==0) return x; else return gcd(y,x%y); } void add(int a1,int a2,int b1,int b2) { int n1=a1*b2+a2*b1; int n2=a2*b2; int temp=gcd(n1,n2); if(temp<0) temp=-temp; printf("%d/%d\n",n1/temp,n2/temp); } void mul(int a1,int a2,int b1,int b2) { int n1=a1*b1; int n2=a2*b2; int temp=gcd(n1,n2); if(temp<0) temp=-temp; printf("%d/%d\n",n1/temp,n2/temp); } int main() { int a1,a2,b1,b2; //第一个数和第二个数得分子和分母 char ch; while(scanf("%d/%d %d/%d %c",&a1,&a2,&b1,&b2,&ch)!=EOF) { //printf("%d %d %d %d\n",a1,a2,b1,b2); switch(ch) { case '+': { add(a1,a2,b1,b2); break; } case '-': { add(a1,a2,-b1,b2); break; } case '*': { mul(a1,a2,b1,b2); break; } case '/': { mul(a1,a2,b2,b1); break; } } } return 0; }
#include<stdio.h> int gcd(int x,int y) { return !y? x>0?x:-x:gcd(y,x%y); } int main() { int a1,b1,a2,b2; char c; while(scanf("%d/%d %d/%d %c",&a1,&b1,&a2,&b2,&c)!=-1) { int A,B,C; switch(c) { case '+': A=a1*b2+a2*b1; B=b1*b2; C=gcd(A,B); printf("%d/%d\n",A/C,B/C); break; case '-': A=a1*b2-a2*b1; B=b1*b2; C=gcd(A,B); printf("%d/%d\n",A/C,B/C); break; case '*': A=a1*a2; B=b1*b2; C=gcd(A,B); printf("%d/%d\n",A/C,B/C); break; case '/': A=a1*b2; B=a2*b1; C=gcd(A,B); B<0?printf("%d/%d\n",-A/C,-B/C):printf("%d/%d\n",A/C,B/C); break; default:break; } } return 0; }
//水题,不过做这感觉比较爽:)#include <stdio.h>int Simplify(inta, intb);int main(){int numer0, denom0, numer1, denom1;int numer2, denom2;char oper[1];int res = 0;while(scanf("%d/%d %d/%d %c", &numer0, &denom0, &numer1, &denom1, &oper[0])!=EOF){if(oper[0]=='+'||oper[0]=='-'){denom2 = denom0*denom1;if(oper[0]=='+'){numer2 = numer0*denom1 + numer1*denom0;}else{numer2 = numer0*denom1 - numer1*denom0;}}elseif(oper[0]=='*'||oper[0]=='/'){if(oper[0]=='*'){numer2 = numer0*numer1;denom2 = denom0*denom1;}else{numer2 = numer0*denom1;denom2 = denom0*numer1;}}res = Simplify(numer2, denom2);denom2 /= res;numer2 /= res;if(denom2<0){printf("-%d/%d\n", numer2, -denom2);}else{printf("%d/%d\n", numer2, denom2);}}return0;}int Simplify(int a, int b){int t;while(b!=0){t = a % b;a = b;b = t;}return a;}
//不服,给我一个超时的理由!importjava.util.Scanner;publicclassMain {publicstaticvoidmain(String[] args) {Scanner in = newScanner(System.in);while(in.hasNext()){String s1=in.next(),s2=in.next(),op=in.next();String[] split1 = s1.split("/"),split2 = s2.split("/");intup1=Integer.valueOf(split1[0]),down1=Integer.valueOf(split1[1]);intup2=Integer.valueOf(split2[0]),down2=Integer.valueOf(split2[1]);intminComm = down1*down2/maxCommon(down1,down2);intup=0,down=0;switch(op) {case"+":inttimes1=minComm/down1,times2=minComm/down2;down=minComm;up=up1*times1+up2*times2;intmaxComm = maxCommon(down,up);up/=maxComm;down/=maxComm;break;case"-":times1=minComm/down1;times2=minComm/down2;down=minComm;up=up1*times1-up2*times2;if(up<0){maxComm = maxCommon(down,up*=-1);up/=maxComm;down/=maxComm;up*=-1;}elseif(up==0){System.out.println("ERROR");}else{maxComm = maxCommon(down,up);up/=maxComm;down/=maxComm;}break;case"*":up=up1*up2;down=down1*down2;maxComm = maxCommon(down,up);up/=maxComm;down/=maxComm;break;case"/":up=up1*down2;down=down1*up2;maxComm = maxCommon(down,up);up/=maxComm;down/=maxComm;break;}System.out.printf("%d/%d\n",up,down);}}publicstaticintmaxCommon(intm,intn){if(m<n){inttemp=n;n=m;m=temp;}if(m%n==0)returnn;elsereturnmaxCommon(n,m%n);}}
#include <stdio.h> int zdgys(int a,int b) { int r; if(a==0) { return a; } else { while(b!=0) { r=a%b; a=b; b=r; } return a; } } int zxgbs(int a,int b) { return a*b/zdgys(a,b); } int main() { char a[6],b[6],c,tab; int afz,afm,bfz,bfm,i,j,m,n,temp; while(scanf("%s%s%c%c",a,b,&tab,&c)!=EOF) { afz=0;afm=0;bfz=0;bfm=0; for(i=0;a[i]!='/';i++) { afz=afz*10+a[i]-'0'; } for(;a[i]!='\0';i++) { if(a[i]>='0'&&a[i]<='9') { afm=afm*10+a[i]-'0'; } } for(i=0;b[i]!='/';i++) { bfz=bfz*10+b[i]-'0'; } for(;b[i]!='\0';i++) { if(b[i]>='0'&&b[i]<='9') { bfm=bfm*10+b[i]-'0'; } } if(c=='+') { m=afz*zxgbs(afm,bfm)/afm+bfz*zxgbs(afm,bfm)/bfm; n=zxgbs(afm,bfm); printf("%d/%d\n",m/zdgys(m,n),n/zdgys(m,n)); } else if(c=='-') { m=afz*zxgbs(afm,bfm)/afm-bfz*zxgbs(afm,bfm)/bfm; n=zxgbs(afm,bfm); if(m>0) { printf("%d/%d\n",m/zdgys(m,n),n/zdgys(m,n)); } else if(m==0) { printf("0\n"); } else if(m<0) { printf("-%d/%d\n",-m/zdgys(-m,n),n/zdgys(-m,n)); } } else if(c=='*') { m=afz*bfz;n=afm*bfm; printf("%d/%d\n",m/zdgys(m,n),n/zdgys(m,n)); } else if(c=='/') { temp=bfz;bfz=bfm;bfm=temp; m=afz*bfz;n=afm*bfm; printf("%d/%d\n",m/zdgys(m,n),n/zdgys(m,n)); } } return 0; }
#include<bits/stdc++.h> using namespace std; int main() { int a1,b1,a2,b2,g; char _1,_2,op; while(cin>>a1>>_1>>b1>>a2>>_2>>b2>>op) { switch(op) { case'+':a1=a1*b2+b1*a2; b1*=b2; g=abs(__gcd(a1,b1)); cout<<to_string(a1/g)+"/"<<to_string(b1/g)<<endl; break; case'-':a1=a1*b2-b1*a2; b1*=b2; g=abs(__gcd(a1,b1)); cout<<to_string(a1/g)+"/"<<to_string(b1/g)<<endl; break; case'*':a1*=a2; b1*=b2; g=abs(__gcd(a1,b1)); cout<<to_string(a1/g)+"/"<<to_string(b1/g)<<endl; break; case'/': a1*=b2; b1*=a2; g=abs(__gcd(a1,b1)); cout<<to_string(a1/g)+"/"<<to_string(b1/g)<<endl; break; default:break; } } return 0; }
#include<bits/stdc++.h> using namespace std; inline int stringint(string x) { long long temp=0; int a=1; int length=x.size(); for(int i=length-1;i>=0;i--) { temp+=a*(x[i]-'0'); a*=10; } return temp; } inline void Print(int x1,int x2,int y1,int y2,string h3) { if(h3=="+"||h3=="-") { while(x2!=y2) { int temp=x2; x2*=y2; x1*=y2; y2*=temp; y1*=temp; } if(h3=="+") { int g; int res=x1+y1; while((g=__***(res,x2))!=1) { res/=g; x2/=g; } cout<<res<<"/"<<x2<<endl; } else { int g,d=1; int res=x1-y1; if(res<0) { d=0; res=-res; } while((g=__***(res,x2))!=1) { res/=g; x2/=g; } if(d) { cout<<res<<"/"<<x2<<endl; } else { cout<<"-"<<res<<"/"<<x2<<endl; } } } else if(h3=="*") { int g; int x3=x1*y1; int x4=x2*y2; while((g=__***(x3,x4))!=1) { x3/=g; x4/=g; } cout<<x3<<"/"<<x4<<endl; } else { int g; int x3=x1*y2; int x4=x2*y1; while((g=__***(x3,x4))!=1) { x3/=g; x4/=g; } cout<<x3<<"/"<<x4<<endl; } } int main() { string h1,h2,h3; int i,j; while(cin>>h1>>h2>>h3) { for(i=0;;i++) { if(h1[i]=='/') break; } int x1=stringint(h1.substr(0,i)); int x2=stringint(h1.substr(i+1)); for(j=0;;j++) { if(h2[j]=='/') break; } int y1=stringint(h2.substr(0,j)); int y2=stringint(h2.substr(j+1)); Print(x1,x2,y1,y2,h3); } }
#include<cstdio> (802)#include<cstdlib> int a,b,c,d; char x; void ans() { if(x=='+') { int k=b*d,z=a*d+b*c; a=z,b=k; } else if(x=='-') { int k=b*d,z=a*d-b*c; a=z,b=k; } else if(x=='*') { int k=b*d,z=a*c; a=z,b=k; } else if(x=='/') { int k=b*c,z=a*d; a=z,b=k; } int k=abs(a)>abs(b)?abs(b):abs(a); if(abs(a)==1 || abs(b)==1) return ; for(int i=k;i>1;i--) { if(abs(a)%i==0 && abs(b)%i==0) {a=a/i;b=b/i;return;} } return ; } int main() { while(scanf("%d/%d %d/%d %c",&a,&b,&c,&d,&x)!=EOF) { ans(); printf("%d/%d\n",a,b); } return 0; }
本题的关键是最大公因数
、最小公倍数
的求解。
两数的最大公因数
求解常用辗转相除法
,比如a,b两数(假设a >= b)
while (a % b != 0) { b’ 赋值为 a / b 余数 (即 a % b) a‘ 赋值为 b a = a’, b = b' }
两数的最小公倍数
求解有个数学规律
a、b最小公倍数 = a * b / (a、b最大公因数)
#include <iostream> (720)#include <math.h> using namespace std; // 求number1、number2的最大公因数 int gcd(int number1, int number2) { int tempNum = 0; //保持number1不小于number2 if (number1 < number2) { //借助tempNum,将number1、number2进行交换 tempNum = number1; number1 = number2; number2 = tempNum; } //判断number1是否能整除number2 while (number1 % number2 != 0) { //ba余数赋给tempNum tempNum = number1 % number2; //把number2赋给number1,tempNum赋给number2 //由于进行求余时,number2是除数,tempNum是余数,所以number2 > tempNum //赋值操作后继续维持了 number1 > number2 number1 = number2; number2 = tempNum; } return number2; } // 求number1、number2的最小公倍数 int lcm(int number1, int number2) { //最小公倍数 = 两数相乘 / 最大公因数 return number1 * number2 / gcd(number1, number2); } int main(int argc, const char * argv[]) { char op = '\0'; // 分数numerator1/denominator1,参数1 分数numerator2/denominator2 参数2 int numerator1 = 1, denominator1 = 1, numerator2 = 1, denominator2 = 1; //scanf返回值为正确输入数据的变量个数,当一个变量都没有成功获取数据时,此时返回-1 while (scanf("%d/%d %d/%d %c", &numerator1, &denominator1, &numerator2, &denominator2, &op) != - 1) { //记录结果是否为负数 bool flag = false; //分数numerator3/denominator3,结果 int numerator3 = 0, denominator3 = 0; if (op == '+') { //处理分数加法,先分母同分,然后分子与分母交叉相乘 denominator3 = denominator1 * denominator2; numerator3 = numerator1 * denominator2 + numerator2 * denominator1; } if (op == '-') { //处理分数减法,先分母同分,然后分子与分母交叉相乘 denominator3 = denominator1 * denominator2; numerator3 = numerator1 * denominator2 - numerator2 * denominator1; if (numerator3 < 0) { //这里单独记录负号,是因为求解公因数、公倍数是不能有负数 flag = true; numerator3 = -numerator3; } } if (op == '*') { //处理分数乘法,分母相乘,分子相乘 denominator3 = denominator1 * denominator2; numerator3 = numerator1 * numerator2; } if (op == '/') { //处理分数除法,分母1 分子2 相乘作分母,分子1 分母2 相乘 作分子 denominator3 = denominator1 * numerator2; numerator3 = numerator1 * denominator2; } if (numerator3 == 0) { printf("0\n"); } else { //分子、分母分别除最大公因数进行约分 int tempNum = gcd(numerator3, denominator3); numerator3 /= tempNum; denominator3 /= tempNum; //如果是减法可能产生负数,因此需要输出负号 printf((flag ? "-%d/%d\n" : "%d/%d\n"), numerator3, denominator3); } } return 0; }
//30以内的质数只有2,3,5,7,11,13,17,19,23,29 #include <stdio.h> #include <stdlib.h> int prime[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; int is_relative(int a, int b) { for(int i = 0; i < 10; i++) { if(a % prime[i] == 0 && b % prime[i] == 0) return prime[i];//不互质,有因数prime[i] } return 1;//互质 } int main() { int a1, b1, a2, b2; char sign; int temp1, temp2; while(~scanf("%d/%d %d/%d %c", &a1, &b1, &a2, &b2, &sign)) { int x; if(sign == '+') { temp2 = b1 * b2; temp1 = a1*b2 + a2*b1; } else if(sign == '-') { temp2 = b1 * b2; temp1 = a1*b2 - a2*b1; } else if(sign == '*') { temp2 = b1 * b2; temp1 = a1 * a2; } else { temp2 = a2 * b1; temp1 = a1 * b2; } if(temp1 == temp2) temp1 = temp2 = 1; while((x = is_relative(temp1, temp2)) != 1) { temp1 = temp1/x; temp2 = temp2/x; } printf("%d/%d\n", temp1, temp2); } }
//可能不是你的程序真的超时,而是你的输入没有加入!=EOF,真的牛皮 #include <iostream> #include <string> #include <algorithm> #include <cmath> using namespace std; int MinCommonMultiple(int a, int b) { int minnum = 0; for (int i = max(a,b);;i++) { if (i%a == 0 && i%b == 0) { minnum = i; break; } } return minnum; } int MaxConventionNumber(int a, int b) { int maxnum = 0; for (int i = min(a, b);i >= 2;i--) { if (a%i == 0 && b%i == 0) { maxnum = i; break; } } return maxnum; } //约分 void reduction(int &a0, int &a1) { if (a0 < 0) { a0 = -a0; cout << '-'; } if (a0 == 0) { cout << a0 << endl; return; } //得到最大公约数 int maxnum = MaxConventionNumber(a0, a1); if (maxnum != 0) { //约分 a0 /= maxnum; a1 /= maxnum; } cout << a0 << '/' << a1 << endl; } //通分 void reverse_red(int &a0, int &a1, int &b0, int &b1) { if (a1 != b1) { int minnum = MinCommonMultiple(a1, b1); a0 = minnum / a1 * a0; b0 = minnum / b1 * b0; a1 = b1 = minnum; } } int main() { string str0, str1; char ch4; int a0, a1, b0, b1; while (scanf_s("%d/%d %d/%d %c",&a0,&a1,&b0,&b1,&ch4)!=EOF) { if (ch4 == '+') { reverse_red(a0, a1, b0, b1); //通分 a0 += b0; reduction(a0, a1); //约分 } else if (ch4 == '-') { reverse_red(a0, a1, b0, b1); a0 -= b0; reduction(a0, a1); } else if (ch4 == '*') { a0 *= b0; a1 *= b1; reduction(a0, a1); } else if (ch4 == '/') { a0 *= b1; a1 *= b0; reduction(a0, a1); } else { cout << "The operation you inputed was failed." << endl; } } return 0; }
//超时 感觉是死循环另外呀 貌似java全超时了 import java.io.*; import java.util.*; public class Test1012Caculate { public static void main(String[] args) { Scanner in= new Scanner(new BufferedInputStream(System.in)); while (in.hasNext()) { String []a=in.next().split("/"); String []b=in.next().split("/"); int a1=Integer.parseInt(a[0]); int b1=Integer.parseInt(a[1]); int a2=Integer.parseInt(b[0]); int b2=Integer.parseInt(b[1]); char op=in.next().charAt(0); switch (op) { case '+': { int x=a1*b2+a2*b1; int y=b1*b2; int gcd=getGcd(x, y); x=x/gcd; y=y/gcd; System.out.printf("%d/%d\n",x,y); break; } case '-': { int x=a1*b2-a2*b1; int y=b1*b2; int gcd=Math.abs(getGcd(x, y)); x=x/gcd; y=y/gcd; System.out.printf("%d/%d\n",x,y); break; } case '*': { int x=a1*a2; int y=b1*b2; int gcd=getGcd(x, y); x=x/gcd; y=y/gcd; System.out.printf("%d/%d\n",x,y); break; } case '/': { int x=a1*b2; int y=b1*a2; int gcd=getGcd(x, y); x=x/gcd; y=y/gcd; System.out.printf("%d/%d\n",x,y); break; } default: break; } } } public static int getGcd(int p,int q) { if(p%q==0){ return q; } int r= p%q; return getGcd(q,r); } }