前言
这道题有难度,目前还没做出来,结果一直不对,卡在17分的地方,一直在死磕,没磕动,没找到哪有问题,目前已经改错完成了
L1-009 N个数求和
本题的要求很简单,就是求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
一、
思路
目前的思路是堆屎山,平时写代码都是先堆屎山,然后一点点去优化,目前代码还是在一个屎山状态
思路就是先给所有的分数通分,先整理所有的分母,求所有分母的最小公倍数,接着通过所有分母的最小公倍数与该分数去求得这个分数通分分子需要乘多少,然后做到通分,累积分子,整合分子分母,然后把分数最简化,这是目前的思路,不清楚代码具体哪里出了漏斗
代码部分
#include <stdio.h>
#include <math.h>
struct num{
long int num1;
long int num2;
};//定义一个结构体来表示分数
struct num number[100] = {0};//定义一个结构体数组存放所有分数
int lcm(int a,int b)//求每个分母的最小公倍数
{
int j,num1,num2;
num1 = a;num2 = b;
if(a>=b)
{
while(b!=0)
{
j = b;
b = a%b;
a = j;
}
return num1*num2/j;
}
else if(a<b)
{
while(a!=0)
{
j = a;
a = b%a;
b = j;
}
}
return num1*num2/j;
}
int gcd(int a,int b)//求最终结果的最小公约数,做到分数最简化
{
int j;
if(a>=b)
{
while(b!=0)
{
j = b;
b = a%b;
a = j;
}
return a;
}
else if(a<b)
{
while(a!=0)
{
j = a;
a = b%a;
b = j;
} return b;
}
}
int main()
{
int count,i,key,sum = 0,l = 0;//定义了一些乱七八糟的变量
//count是分数的数量,key是最小公倍数,sum是分子和,l是最大公约数
scanf("%d",&count);//输入分数的个数
for(i = 0;i < count;i++)//遍历输入各个分数
scanf("%d/%d",&number[i].num1,&number[i].num2);
for(i = 1;i < count;i++)//求最小公倍数来表示分母
key = lcm(number[i].num2,number[i-1].num2);
for(i = 0;i < count;i++)//求分子和
{
number[i].num1 *= key/number[i].num2;
sum += number[i].num1;
}
// printf("%d\n",sum);
l = abs(gcd(sum,key)); //求最大公约数,取绝对值
// printf("%d\n",l);
sum /= l;//求最简化分子
key /= l;//求最简化分母
if(sum%key == 0)printf("%d",sum/key);//无分数
else if(sum/key == 0)printf("%d/%d",sum%key,abs(key));//无整数
else printf("%d %d/%d",sum/key,abs(sum%key),abs(key));//全都有
}
二、
之后就直接把之前的推翻了重新做了一遍,也没看到第一个的问题在哪,第二遍做的思路就把第一遍的推翻了,不去全部的去通分,一个一个去通分,做加法,也就是每次输入之前都已经做完了一步运算,这遍神奇般的做对了。
下面就直接看看代码吧
#include <stdio.h>
long long int gcd(long long int a,long long int b)
//这个地方还是和之前一样,求一个最大公约数,去化简分数(辗转相除法)
{
long long int j;
if(a>=b)
{
while(b!=0)
{
j = b;
b = a%b;
a = j;
}
return a;
}
else if(a<b)
{
while(a!=0)
{
j = a;
a = b%a;
b = j;
} return b;
}
}
int main()
{
int N,i,j;
scanf("%d",&N);//输入分数的个数
long long int num1,num2,sum1 = 0,sum2 = 1;
for(i = 0;i<N;i++)
{
scanf("%lld/%lld",&num1,&num2);//输入分数
sum1 *= num2;
sum1 += num1 * sum2;
sum2 *= num2;
//做两个分数的加法,先获取分母的值,然后分母乘分子的值直接相交求和,分母只做乘法
j = gcd(sum1,sum2);//求最大公约数
sum1 /= j;
sum2 /= j;//化简
}
if(sum1%sum2 == 0)printf("%lld",sum1/sum2);//整数
else if(sum1/sum2 == 0)printf("%lld/%lld",sum1%sum2,sum2);//纯分数
else printf("%lld %lld/%lld",sum1/sum2,sum1%sum2,sum2);//整数分数混合
}
辗转相除法
这是最常用的方法,基于以下原理:两个整数a和b(假设a > b),它们的最大公约数等于b和a % b(a除以b的余数)的最大公约数。
步骤:
如果b为0,则最大公约数是a。
否则,将a赋值为b,将b赋值为a % b,重复上述过程。
总结
这道题目有难度,我感觉,难度在于,以一种屎山的方式去堆代码,会出现一些奇奇怪怪的问题,实在没有思路去堆屎山,代码能少写就少写,写的多了,就肯定会有逻辑上面的漏洞不好发现,总而言之,练得少还是
以上所有代码均为自己编写,本人水平有限,如果有哪里出错或者有更好的解法可以与我私信或在评论区里进行讨论