用python的math.sqrt()配合海伦公式算面积的时候,有一个被忽略的问题,就是大数据的情况下,python的计算精度问题。
三角形(302828,302828,302829)就是一个很好的例子。import math
def area(a,b,c):
p = (a+b+c)/2
s = math.sqrt(p*(p-a)*(p-b)*(p-c))
return s
print(area(302828,302828,30282))
答案是39709429597.0。但实际上,该三角形底边上的高为262256.45230146387,是个无理数,面积不会是真正的“整数”,这只不过是被python四舍五入了。
所以,这道题的关键在于(1)避开sqrt()函数直接作用于大的数,(2)将计算次数从上亿次降下来。
对于一个编程渣来讲,最好的办法就是: 编程渣,数学来凑!
不得不承认,我把这道题做成了数学题。后面是长长的数学推理,可跳过。
假定第三边大于三角形的两腰,那么设三边为m,m,m+1。那么根据海伦公式,
p=(m+m+m+1)/2=(3m+1)/2
S= √((3m+1)(m+1)(m+1)(m-1)/16)
所以,m必须是奇数才可以。设m=2k+1,那么代入,有
S=(k+1)√(k(3k+2))
显然,k与3k+2没有大于2的公因子。
假设两者互质,那么k和3k+2 都必须同时是完全平方数才能确保面积是整数,可以设k=x^2,检测3x^2+2是否为整数。这时,三角形的三边为2*x^2+1, 2*x^2+1,2*x^2+2,根据边长范围可得,x不大于12910。
假设两者不互质,那么设k=2y,那么
S=2(2y+1)√(y(3y+1))
Y与3y+1必然互质,所以y和(3y+1)必须是完全平方数,设y = x^2,检测 3*x^2 + 1 是否为完全平方数即可。此时,三角形的三边为 4^x2+1, 4^x2+1, 4^x2+2,x不大于9129。
同样的,假定第三边小于三角形的两腰时,可以得到后面的结论:
三角形三边为2*x^2-1, 2*x^2-1,2*x^2-2, x不大于12910,3*x^2-2须为完全平方数。
三角形三边为4*x^2-1, 4*x^2-1,4*x^2-2, x不大于9129,3*x^2-1须为完全平方数。
上代码:import math
pri_sum = 0
#case1
for i in range(1,int(math.sqrt(10**9/3/2))+1):
test = math.sqrt(3*i*i+2)
if round(test)==test:
pri_sum+=sum([2*i*i+1,2*i*i+1,2*i*i+2])
#case2
for i in range(1,int(math.sqrt(10**9/3/4))+1):
test = math.sqrt(3*i*i+1)
if round(test)==test:
pri_sum+=sum([4*i*i+1,4*i*i+1,4*i*i+2])
#case3
for i in range(2,int(math.sqrt(10**9/3/2))+1):
test = math.sqrt(3*i*i-2)
if round(test)==test:
pri_sum+=sum([2*i*i-1,2*i*i-1,2*i*i-2])
#case4
for i in range(1,int(math.sqrt(10**9/3/4))+1):
test = math.sqrt(3*i*i-1)
if round(test)==test:
pri_sum+=sum([4*i*i-1,4*i*i-1,4*i*i-2])
print(pri_sum)
计算结果为518408346。可以预见,结果是秒出的。
所找到的三角形为:5 5 6
65 65 66
901 901 902
12545 12545 12546
174725 174725 174726
2433601 2433601 2433602
33895685 33895685 33895686
17 17 16
241 241 240
3361 3361 3360
46817 46817 46816
652081 652081 652080
9082321 9082321 9082320
126500417 126500417 126500416
做成了数学题,也是醉了。 |