L1-009. N个数求和
时间限制
400 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越
本题的要求很简单,就是求N个数字的和。麻烦的是,这些数字是以有理数“分子/分母”的形式给出的,你输出的和也必须是有理数的形式。
输入格式:
输入第一行给出一个正整数N(<=100)。随后一行按格式“a1/b1 a2/b2 ...”给出N个有理数。题目保证所有分子和分母都在长整型范围内。另外,负数的符号一定出现在分子前面。
输出格式:
输出上述数字和的最简形式 —— 即将结果写成“整数部分 分数部分”,其中分数部分写成“分子/分母”,要求分子小于分母,且它们没有公因子。如果结果的整数部分为0,则只输出分数部分。
输入样例1:5 2/5 4/15 1/30 -2/60 8/3输出样例1:
3 1/3输入样例2:
2 4/3 2/3输出样例2:
2输入样例3:
3 1/3 -1/6 1/8输出样例3:
7/24
解题思路:
这道题目我的基本思路是,将输入的一个个分数,都看成字符串,然后提取出分子和分母,设当前和值为FZ/FM(FZ是汉语分子的首字母缩写,FM是汉语分母的首字母缩写)
则现在输入一个串,例如 -2/5,
则我先求出这个分数的分子fz,分母fm,
则当前和值为 : (FZ/FM)+ (fz/fm)
通分得: = (FZ*fm+FM*fz)/(FM*fm)
然后求(FZ*fm+FM*fz)
但是对于这样的想法,也是有普通情况的。比如当前输入的这个串fz是等于0的,则不管分母是什么,这个数都不用加。
比如测试数据:
2
2/5 0/1
第二个分数分子是0,则这个数是0,则直接跳过不要考虑了。
如果有这种情况:
4
2/5 0/1 -2/5 3/5
则当要加上第三个数时,(FZ*fm+FM*fz) 分子得0,这时候千万不要再去求公约数了。当前的和值为0.则让FZ = 0 FM = 1;这样的话输入下一个分数时,FZ/FM + fz/fm 其分子 FZ*fm+FM*fz = 0*fm + 1*fz = fz;其分母 FM*fm = 1*fm = fm ,刚好就等于 fz/fm = 0+fz/fm#include<iostream> #include<stdio.h> #include<algorithm> #include<string.h> #include<cmath> #define INF 999999 using namespace std; /** int gcd(int x, int y) ///递归方法,求最大公约数 { return y==0?x:gcd(y,x%y); } **/ int FZ,FM,fz,fm; ///分子分母 int _max(int n,int m) ///辗转相除法求n和m的求最大公约数 { int temp,r; n = abs(n); ///都取绝对值,先不用考虑符号 m = abs(m); ///都取绝对值,先不用考虑符号 if(n < m) ///辗转相除,我要让n是大的数,m是小的数,因此这里要进行比较 { temp = n; n = m; m = temp; } while(1) ///辗转相除法 { r = n%m; if(r != 0) { n = m; m = r; } else return m; } } void fun(char str[]) ///求分子,分母 { int len; int i; len = strlen(str); fz = 0; if(str[0]=='-') ///分子是负数 { for(i = 1; i < len; i++) { if(str[i]=='/') ///到除号截止 break; fz = fz*10 + (str[i]-'0'); } fz = -1*fz; ///变成它的相反数 } else ///分子是正数 { for(i = 0; i < len; i++) { if(str[i]=='/') break; fz = fz*10 + (str[i]-'0'); } } fm = 0; ///分母是0 i++; ///跳过分号 if(str[i]=='-') ///如果分母是负数 { for(i = i+1;i < len; i++) ///跳过负号 { fm = fm*10 + (str[i]-'0'); } fm = -1*fm; ///取相反数 } else ///分母是正数 { for(; i < len; i++) { fm = fm*10 + (str[i]-'0'); } } } int main() { char s[500]; int N; ///N个分数相加 while(~scanf("%d",&N)) { scanf("%s",s); ///先输入第一个分数 fun(s); ///求分子分母 if(fz == 0) ///第一个数是0 { FZ = 0; FM = 1; } else { FZ = fz; FM = fm; } for(int i = 1; i < N; i++) { scanf("%s",s); fun(s); ///求分子分母 if(fz == 0) ///代表当前输入的值为0,不用加,直接跳过 continue; fz = FZ*fm + FM*fz; ///这两部是通分 fm = FM*fm; if(fz == 0) ///说明当前分子是0,即当前和值变为0 { FZ = 0; FM = 1; } else ///否则求最大公约数,化简分数 { int num = _max(fz,fm); ///求最大公约数 FZ = fz/num; ///化简分数 FM = fm/num; ///化简分数 } } if(FZ == 0) ///如果分子为0,则输出0 printf("0\n"); else if((FZ>0&&FM>0)||(FZ<0&&FM<0)) ///分子分母同号 { FZ = abs(FZ); ///不管正负,直接求绝对值 FM = abs(FM); if(FZ%FM == 0) ///如果能除尽 printf("%d\n",FZ/FM); else { int t = FZ/FM; if(t) ///是假分数 printf("%d %d/%d\n",t,FZ-t*FM,FM); else printf("%d/%d\n",FZ,FM); } } else if((FZ>0&&FM<0)||(FZ<0&&FM>0)) { printf("-"); ///先输出负号 FZ = abs(FZ); FM = abs(FM); if(FZ%FM == 0) printf("%d\n",FZ/FM); else { int t = FZ/FM; if(t) ///是假分数 printf("%d %d/%d\n",t,FZ-t*FM,FM); else printf("%d/%d\n",FZ,FM); } } } return 0; }