方法一:
非常暴力的做法,把所有的分母乘在一起构成总分母,然后通分相加
import math
n = int(input())
strs = input().split()
li = []
down = 1
# 把所有的分母乘在一起
for s in strs:
li.append(list(map(int,s.split('/'))))
down *= int(s[s.find('/') + 1:])
for i in range(len(li)):
a = li[i][0]
b = li[i][1]
li[i][0] = a * (down // b)
li[i][1] = down
up = 0
# 通分相加
for i in range(len(li)):
up += li[i][0]
_gcd = math.gcd(up,down)
# 约分
up //= _gcd
down //= _gcd
# 如果结果是整数,则只需输出整数部分(可以整除)
# 判断一个分数是不是整数,只需判断分母是否为1
if down == 1:
print(up)
else: # 不能整除
number = up // down
if number == 0:# 如果整数部分是 0,则只需输出小数部分
print(f'{up}/{down}')
else:# 整数部分不是0,则先输出整数部分,再输出小数部分
up -= number * down
print(f'{number} {up}/{down}')
方法二:
使用python中fractions模块的Fraction类 fraction n.分数
from fractions import Fraction
n = int(input())
s = Fraction(0,1) # 初始化分数为0 / 1
for i in input().split():
s += Fraction(i) # 分母相加
up,down = s.numerator,s.denominator # numerator n.分子 denominator n.分母
# 如果结果是整数,则只需输出整数部分(可以整除)
# 判断一个分数是不是整数,只需判断分母是否为1
if down == 1:
print(up)
else: # 不能整除
number = up // down
if number == 0:# 如果整数部分是 0,则只需输出小数部分
print(f'{up}/{down}')
else:# 整数部分不是0,则先输出整数部分,再输出小数部分
up -= number * down
print(f'{number} {up}/{down}')
方法三:
以上两种方法只有python中可以使用,因为第一种方法C++会报int
和long long
,第二种方法是调用python的模块的,下面给出第三种方法:
$$
\frac{up}{down} + \frac{a}{b} = \frac{up \times b + a \times down}{down \times b}
$$
import math
n = int(input())
strs = input().split()
up,down = 0,1
for s in strs:
a,b = map(int,s.split('/'))
"""
这两条语句不能写反了,若先写down = down * b,再写up = up * b + a * down
则down的值被改变了,就错了
"""
up = up * b + a * down
down = down * b
# 勤约分
t = math.gcd(up,down)
up //= t
down //= t
_gcd = math.gcd(up,down)
# 约分
up //= _gcd
down //= _gcd
# 如果结果是整数,则只需输出整数部分(可以整除)
# 判断一个分数是不是整数,只需判断分母是否为1
if down == 1:
print(up)
else: # 不能整除
number = up // down
if number == 0:# 如果整数部分是 0,则只需输出小数部分
print(f'{up}/{down}')
else:# 整数部分不是0,则先输出整数部分,再输出小数部分
up -= number * down
print(f'{number} {up}/{down}')
还可以对方法三进行一个优化,防止down * b
爆int
和long long
,即先求down
和b
的最小公倍数,再通分,该优化仅对C++用处比较大,python完全没必要这么写
import math
n = int(input())
strs = input().split()
up,down = 0,1
for s in strs:
a,b = map(int,s.split('/'))
lcm = down * b // math.gcd(down,b)# 找出两个相加分数的分母的最小公倍数
up = lcm // down * up + lcm // b * a # 通分
down = lcm
# 勤约分
t = math.gcd(up,down)
up //= t
down //= t
_gcd = math.gcd(up,down)
# 约分
up //= _gcd
down //= _gcd
# 如果结果是整数,则只需输出整数部分(可以整除)
# 判断一个分数是不是整数,只需判断分母是否为1
if down == 1:
print(up)
else: # 不能整除
number = up // down
if number == 0:# 如果整数部分是 0,则只需输出小数部分
print(f'{up}/{down}')
else:# 整数部分不是0,则先输出整数部分,再输出小数部分
up -= number * down
print(f'{number} {up}/{down}')
这个优化一定要注意的点:
lcm = down * b // math.gcd(down,b)
这一行代码千万不能写成lcm = down * b / math.gcd(down,b)
,虽然你知道该式子最后的结果一定可以除尽,但是最后是个浮点数,后面要调用t = math.gcd(up,down)
,浮点数是不能传人gcd()
函数的形参的,所以这一行会报错
那么这一行代码改成lcm = int(down * b / math.gcd(down,b))
呢?看似可行,但实际错了,看以下的例子就知道为什么了
例子:
print(998244359987710471)
print(998244359987710471 // 1)
print(998244359987710471 / 1)
print(int(998244359987710471 / 1))
"""
998244359987710471
998244359987710471
9.982443599877105e+17
998244359987710464
"""
可见,float类型存在精度问题
因此,如果能确定除法的运算结果为整数,就最好不要用/
,用//