L1-009. N个数求和

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



  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值