题目: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);
}
有没有大佬帮忙看看是哪里没考虑到吗?目前找不出是哪里进行的扣分。