PTA天梯赛练习集-L1-009 N个数求和--求解答(未获取满分,但不清楚原因)

题目:L1-009 N个数求和

本题的要求很简单,就是求N个数字的和。麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式。

输入格式:

输入第一行给出一个正整数N(≤100)。随后一行按格式a1/b1 a2/b2 ...给出N个有理数。题目保证所有分子和分母都在长整型范围内。另外,负数的符号一定出现在分子前面。

输出格式:

输出上述数字和的最简形式 —— 即将结果写成整数部分 分数部分,其中分数部分写成分子/分母,要求分子小于分母,且它们没有公因子。如果结果的整数部分为0,则只输出分数部

分。

输入样例:

我的解题思路:

        题目意思很简单,脉络也很清楚,只要求出输入的分数的最小公倍数,然后分子约分取余,即可解答此题 。

        因为刚学完结构,想试着用结构和字符串解出此题 。在输入n个分数的时候,以空格进行划分,将分数存入一个二维数组内。创建一个结构体 ,其具体类型为long int 的两个值(分别是分子和分母)。想办法把二维数组内的字符串,以分子分母的形式存入结构体。此时结构体内的分子分母是long int 型。再对其进行相关运算即可。如 求取其分母的最小公倍数。以此展开。

解题过程:

1、主函数中获取输入,将需计算的分数存入二维数组内,调用后续的处理函数。(PS 此处关键点在于如何划分输入的分数存入到二维数组)。

int main()
{
    int num;
    scanf("%d",&num);
    char  FraStr[num][81];  ///声明一个二维数组
    struct Fraction Fenshu[num];    ///创建一个分数结构体
    int i = 0;
    getchar(); ///获取缓冲区的换行符
    char str ;
    for(int j=0;j<num;++j)
    {
        int k=0;
        int flag=1;
        while ((str = getchar() )!= ' ')  ///以空格为单位,划分分数 ,存入数组
        {
            if((str == '\r')||(str == '\n'))break;
            FraStr[j][k] = str;
            k++;
            flag++;
        }
        FraStr[j][flag] = '\0';  ///每个分数最后一位补'\0'变成字符串
    }


//    // 循环打印存入二位数组的分数字符串
//    for (int j = 0; j < num; ++j) {
//        puts(FraStr[j]);
//    }

    ///调用转换函数--字符串格式转正 long int 放入结构体
    Transit(num,81,FraStr,Fenshu);

    return 0;
}

2、把二维数组的分数,以“/”截断,且转换为long int 类型存入结构体数组内。(ps:此处需要注意如何和 字符串一分两半,相应存入结构体的分子分母字段中。我的想法是先确认"/"所在位置,将并将其置为‘\0’,然后此字符串就前后分为两部分即分子和分母)。


///把输入的分数形式的字符串,以“/“截断,转换为long int 将分子分母存入结构体
void Transit(int m,int n,char strArg[m][n],struct Fraction Fenshu[])
{
    for(int i=0;i<m;i++)
    {
        char * fp;
        char * fm;
       fp = strchr(strArg[i],47);
       *fp = '\0';    /// 在"/"这里替换'\0'以进行划分分子分母
       fm = fp+1;    /// 分母的起始位置
       Fenshu[i].FenZi = atol(strArg[i]);  ///将字符串转换为long类型
       Fenshu[i].FenMu = atol(fm);
       //printf("fz: %d    fm: %d \n",Fenshu[i].FenZi,Fenshu[i].FenMu);    //打印分子分母
    }

    long int FM_Number[m];  ///把分母存入数组,方便调用函数进行处理
    for (int i=0;i<m;i++)
    {
        FM_Number[i] = Fenshu[i].FenMu;
    }

    long int  least_multiple; //定义最小公倍数
    int FM_Num_Len =  sizeof(FM_Number) / sizeof(long int);
    least_multiple = MinGongbeishu(FM_Number,FM_Num_Len); ///求最小公倍数


    ///根据最小公倍数,是的结构体数组中的分子分母同时相应扩大
    expand(Fenshu,least_multiple,m);

}

3、将结构体的分母单独放在一个数组内,对其进行求取最小公倍数(此举是便于模块化处理,方便调用各种函数),此处想法是两个数两个数的进行比较,然后最后得其最小公倍数。但是需要注意一点,在求取最大公因式的时候,要对比进行求绝对值,以便后面负数的计算。

PS:最小公倍数等于两数相乘除于两数的最大公约数(gbs=a*b/gys)

long int MinGongbeishu(long int num[],int num_Len)
{
    int len = num_Len;

    /// 两数相比 求其最小公倍数,然后将至存放在第二个数的位置   比较length - 1次
    for (int i = 0; i < len-1; ++i) {
        num[i+1] = (num[i]*num[i+1])/twoNum_GCD(num[i],num[i+1]);
    }
    return num[len-1];
}
int twoNum_GCD(long int m,long int n)
{
    if(n==0)return abs(m);
    else return twoNum_GCD(n,m%n);
}

4、通过最小公倍数,对结构体数组内的分子分母进行处理。分母统一为最小公倍数,分母进行相应的倍数扩大。然后对输出格式进行整理。(注意最后的结果格式如 n x/y  ;n为零或者x为零的情况)

void expand(struct Fraction FS[],int multiplier,int m)
{
    long int  sum = 0;
    long int result ;
    long int result_fenzi ;
    ///分母统一 为最小公倍数   分子同步扩大相应倍数
    for (int i = 0; i < m; ++i) {
        int calculate = multiplier/FS[i].FenMu;
        FS[i].FenMu = multiplier;
        FS[i].FenZi = calculate * FS[i].FenZi;
    }

    分子求和
    for (int i = 0; i < m; ++i) {
        sum = sum + FS[i].FenZi;
    }
    
    result = sum/multiplier;  /// 获取假分数 即输出结果前一个值
    result_fenzi = sum % multiplier;

    求取余后的分子 与分母的最大公因子,最后再约分一次,防止没化简
    long int gyz = twoNum_GCD(result_fenzi,multiplier);

    ///如果分数值小于1,直接显示分数
    if(result == 0 && result_fenzi != 0) printf("%ld/%ld",result_fenzi/gyz,multiplier/gyz);
    else if(result != 0 && result_fenzi == 0 )printf("%ld",result);
    else printf("%ld %ld/%ld",result,result_fenzi/gyz,multiplier/gyz);
}

OK。题目到此就算解决完了。可以看到,用了很多函数和相关知识,如输入的字符串分段存入数组,字符串分段并转换值存入结构体,以及求取数组值的最小公倍数,两数的最大公约数等。

但是不知道哪里有问题,没有获取满分。扣了5分。试了多种测试用例,觉得好像没什么问题。

测试用例:

完整代码:

#include<stdio.h>
#include<string.h>
#include<math.h>

struct Fraction
{
    long int FenZi;  ///分子
    long int FenMu;  ///分母
};

///把字符串的分数转换为long int 型,且存入结构体中
void Transit(int m,int n,char strArg[m][n],struct Fraction Fenshu[]);

///求输入数组的最小公倍数
long int MinGongbeishu(long int num[],int num_Len);

   求两个数的最大公因子
int twoNum_GCD(long int m,long int n);

提供一个最小公倍数分母,使得结构体 中的分子分母进行相应扩大  统一分母
void expand(struct Fraction FS[],int multiplier,int m);

int main()
{
    int num;
    scanf("%d",&num);
    char  FraStr[num][81];
    struct Fraction Fenshu[num];
    int i = 0;
    getchar(); ///获取缓冲区的换行符
    char str ;
    for(int j=0;j<num;++j)
    {
        int k=0;
        int flag=1;
        while ((str = getchar() )!= ' ')  ///以空格为单位,划分分数 ,存入数组
        {
            if((str == '\r')||(str == '\n'))break;
            FraStr[j][k] = str;
            k++;
            flag++;
        }
        FraStr[j][flag] = '\0';  ///每个分数最后一位补'\0'变成字符串
    }


//    // 循环打印存入二位数组的分数字符串
//    for (int j = 0; j < num; ++j) {
//        puts(FraStr[j]);
//    }

    ///调用转换函数--字符串格式转正 long int 放入结构体
    Transit(num,81,FraStr,Fenshu);

    return 0;
}


///把输入的分数形式的字符串,以“/“截断,转换为long int 将分子分母存入结构体
void Transit(int m,int n,char strArg[m][n],struct Fraction Fenshu[])
{
    for(int i=0;i<m;i++)
    {
        char * fp;
        char * fm;
       fp = strchr(strArg[i],47);
       *fp = '\0';    /// 在"/"这里替换'\0'以进行划分分子分母
       fm = fp+1;    /// 分母的起始位置
       Fenshu[i].FenZi = atol(strArg[i]);  ///将字符串转换为long类型
       Fenshu[i].FenMu = atol(fm);
       //printf("fz: %d    fm: %d \n",Fenshu[i].FenZi,Fenshu[i].FenMu);    //打印分子分母
    }

    long int FM_Number[m];  ///把分母存入数组,方便调用函数进行处理
    for (int i=0;i<m;i++)
    {
        FM_Number[i] = Fenshu[i].FenMu;
    }

    long int  least_multiple; //定义最小公倍数
    int FM_Num_Len =  sizeof(FM_Number) / sizeof(long int);
    least_multiple = MinGongbeishu(FM_Number,FM_Num_Len); ///求最小公倍数

    //printf("%ld",least_multiple);


    ///根据最小公倍数,是的结构体数组中的分子分母同时相应扩大
    expand(Fenshu,least_multiple,m);


}

long int MinGongbeishu(long int num[],int num_Len)
{
    int len = num_Len;

    /// 两数相比 求其最小公倍数,然后将至存放在第二个数的位置   比较length - 1次
    for (int i = 0; i < len-1; ++i) {
        num[i+1] = (num[i]*num[i+1])/twoNum_GCD(num[i],num[i+1]);
    }
    return num[len-1];
}


int twoNum_GCD(long int m,long int n)
{
    if(n==0)return abs(m);
    else return twoNum_GCD(n,m%n);
}

void expand(struct Fraction FS[],int multiplier,int m)
{
    long int  sum = 0;
    long int result ;
    long int result_fenzi ;
    ///分母统一 为最小公倍数   分子同步扩大相应倍数
    for (int i = 0; i < m; ++i) {
        int calculate = multiplier/FS[i].FenMu;
        FS[i].FenMu = multiplier;
        FS[i].FenZi = calculate * FS[i].FenZi;
    }

    分子求和
    for (int i = 0; i < m; ++i) {
        sum = sum + FS[i].FenZi;
    }

    result = sum/multiplier;  /// 获取假分数 即输出结果前一个值
    result_fenzi = sum % multiplier;

    求取余后的分子 与分母的最大公因子,最后再约分一次,防止没化简
    long int gyz = twoNum_GCD(result_fenzi,multiplier);

    ///如果分数值小于1,直接显示分数
    if(result == 0 && result_fenzi != 0) printf("%ld/%ld",result_fenzi/gyz,multiplier/gyz);
    else if(result != 0 && result_fenzi == 0 )printf("%ld",result);
    else printf("%ld %ld/%ld",result,result_fenzi/gyz,multiplier/gyz);
}



有没有大佬帮忙看看是哪里没考虑到吗?目前找不出是哪里进行的扣分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值