作者 陈越
单位 浙江大学
本题的要求很简单,就是求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
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
思路:首先题目涉及分子分母的通分和化简,需要会写求最大公因数和最小公倍数的函数
#define ll long long//更直观一些
//求最大公约数
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a % b);
}
// 求最小公倍数
ll lcm(ll a, ll b)
{
return a*b / gcd(a, b);
}
然后接受输入,把分子和分母分别存起来 ,这里负数可以正确地被存在分子数组中
int n;
cin >> n;
vector<ll>fenzi;
vector<ll>fenmu;
for (int i = 0; i < n; i++)
{
ll x, y;
char a;
cin >> x >> a >> y;
fenzi.push_back(x);
fenmu.push_back(y);
既然题目最后要求的是求输入所有分数的和,并且要求最简形式,那么我们肯定要把这些分数都加起来?怎么加起来呢? 我们不妨回想一下在数学中把分数加起来的思路,很简单!就是通分,那么我们就需要遍历fenmu数组,找出分母们的最小公倍数
ll yLast = 1; // 通分后的分母
//找到所有分母的最小公倍数
for (int i = 0; i < n; i++)
{
ll y = fenmu[i];
ll a = lcm(yLast, y); // 计算当前分母和已通分分母的最小公倍数
yLast = a; // 更新通分后的分母
}
分母们的最小公倍数找到之后,我们就可以更新通分后的分子
按照如此的数学思路,用代码实现的思路就是,遍历分子数组,计算通分后的分子,然后开一个pair类型的数组,将通分后的数存进去,
vector<pair<ll, ll>> num; // 存储通分后的分子和分母
for (int i = 0; i < n; i++)
{
ll x = fenzi[i];
ll y = fenmu[i];
num.push_back(make_pair(x * (yLast / y), yLast )); // 通分后的分子和分母
}
// 计算通分后所有分子的和
ll xLast = 0;
for (auto p : num)
{
xLast += p.first;
}
此时我们已经找到了通分后所有分子的和xLast和分母的最小公倍数yLast,只需要对这两个数化简一下就行,即除以它们的最大公因数;
// 约简分数
ll gcdVal = gcd(xLast, yLast);
xLast /= gcdVal;
yLast /= gcdVal;
最后输出,注意题目要求,此处思路在代码注释中详细讲解
// 输出结果
if (xLast == 0) //相加后分子为0
{
cout << "0";
}
else if (xLast % yLast == 0) // 如果分子是分母的整数倍,则只输出整数部分
{
cout << xLast / yLast;
}
else if(xLast/yLast)// 否则输出整数部分和分数部分,整数部分不为0输出整数部分,即该分数大于1
{ //类似于数学中的带分数
cout << xLast / yLast << " " << (xLast% yLast) << "/" << yLast;
}
else//整数部分为0,则不输出整数部分,即该分数小于1
{
cout << (xLast% yLast) << "/" << yLast;
}
完整代码:
#include <vector>
#include <iostream>
#define ll long long
using namespace std;
//求最大公约数
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a % b);
}
// 求最小公倍数
ll lcm(ll a, ll b)
{
return a*b / gcd(a, b);
}
int main()
{
//接受输入,将分子和分母存在数组中
int n;
cin >> n;
vector<ll>fenzi;
vector<ll>fenmu;
for (int i = 0; i < n; i++)
{
ll x, y;
char a;
cin >> x >> a >> y;
fenzi.push_back(x);
fenmu.push_back(y);
}
ll yLast = 1; // 通分后的分母
//找到所有分母的最小公倍数
for (int i = 0; i < n; i++)
{
ll y = fenmu[i];
ll a = lcm(yLast, y); // 计算当前分母和已通分分母的最小公倍数
yLast = a; // 更新通分后的分母
}
vector<pair<ll, ll>> num; // 存储通分后的分子和分母
for (int i = 0; i < n; i++)
{
ll x = fenzi[i];
ll y = fenmu[i];
num.push_back(make_pair(x * (yLast / y), yLast )); // 通分后的分子和分母
}
// 计算通分后所有分子的和
ll xLast = 0;
for (auto p : num)
{
xLast += p.first;
}
// 约简分数
ll gcdVal = gcd(xLast, yLast);
xLast /= gcdVal;
yLast /= gcdVal;
// 输出结果
if (xLast == 0) //相加后分子为0
{
cout << "0";
}
else if (xLast % yLast == 0) // 如果分子是分母的整数倍,则只输出整数部分
{
cout << xLast / yLast;
}
else if(xLast/yLast)// 否则输出整数部分和分数部分,整数部分不为0输出整数部分,即该分数大于1
{ //类似于数学中的带分数
cout << xLast / yLast << " " << (xLast% yLast) << "/" << yLast;
}
else//整数部分为0,则不输出整数部分,即该分数小于1
{
cout << (xLast% yLast) << "/" << yLast;
}
return 0;
}