![](/img/trans.png)
[英]Why isn't my python solution for a Project Euler problem working?
[英]Why isn't my solution to Project Euler 9 working?
问题9:
毕达哥拉斯三联体是一组三个自然数,a <b <c,为此,
a 2 + b 2 = c 2
例如,3 2 + 4 2 = 9 + 16 = 25 = 5 2 。
精确存在一个毕达哥拉斯三联体,其中
a + b + c = 1000
。 找到产品abc。
我的方法是生成三元组,然后检查它们是否满足a + b + c = d
。 为此,我采用Dickson的方法来生成勾股三胞胎(如Wikipedia所述的Dickson方法:要找到x 2 + y 2 = z 2
整数解,请找到正整数r
, s
和t
: r 2 = 2 * s * t
是一个平方,则: x = r + s;
y = r + t
和z = r + s + t
从中我们可以看到r
是任意偶数整数,并且s
和t
是r 2 / 2
因数。
def problem9(d=12):
def dickson(r=6):
factors, triplets, st = [], [], (r**2)/2
for i in range(1, int( sqrt(st)+1 )): # Sqrt optimization
if st % i == 0:
factors += [[r, i, st//i]]
for i in range(len(factors)):
r,s,t = factors[i][0], factors[i][1], factors[i][2]
triplets += [[r+s,r+t,r+s+t]]
return triplets
def tripletSumsMyDValue(triplets):
for tri in triplets:
a,b,c = tri[0],tri[1],tri[2]
if d == int(a + b + c):
return tri
else:
return None
inc = 2
while True:
found = tripletSumsMyDValue(dickson(inc))
if found: return found
else: print(inc,found,'is not!')
inc += 1
令人沮丧的是,您是个天才,执行代码几秒钟后,您意识到自己陷入了无限循环:P
while True:
循环,它应该在达到正确答案(200, 375, 425)
后停止(200, 375, 425)
但结果是无限的。
最令人不安的是,下一个代码可以正常工作,所以请不要指出。 我只想知道我的问题是什么。
def problem9b(d = 12):
inc = 1
while True:
for a in range(1, 100 * inc):
for b in range(1, 100 * inc):
c = (a ** 2 + b ** 2) ** .5
if a + b + c == 1000:
return a, b, c
inc += 1
有一种更简单的方法可以做到这一点。
如果您不去研究编码,而是看数学,那么可以大大简化问题。
我们有两个方程;
a 2 + b 2 = c 2
a + b + c = 1000
因此,将一个替换为另一个:
a 2 + b 2 = (1000 - a - b) 2
0 = 1000 2 - 2000a - 2000b - 2ab
我们还知道a
, b
和c
均<1000
。 因此,我们可以获得满足该方程式的a
和b
的所有组合的列表,然后简单地检查sqrt(a**2 + b**2)
是什么。
您可以在单个(很丑陋,但不是很Python的)列表理解中完成此操作,并且只需要一秒钟。
[[a,b, sqrt(a**2 + b**2)] for a,b in combinations(range(1,1000),2) if 1000000-2000*a-2000*b+2*a*b==0]
[[200,375,425.0]]
list comprehension
是在python中创建列表的快速方法。 通过列表理解创建的任何列表始终可以使用循环以更清晰的方式创建。 您可以在此处阅读有关它们的更多信息 。
这是一个简单的例子:
a = [i for i in range(10)]
只是与以下内容相同:
a = []
for i in range(10):
a.append(i)
这是我给的例子;
[[a,b, sqrt(a**2 + b**2)] for a,b in combinations(range(1,1000),2) if 1000000-2000*a-2000*b+2*a*b==0]
可以这样写:
triplets = []
for a,b in combinations(range(1,1000),2):
if 1000000-2000*a-2000*b+2*a*b==0:
triplets.append([a, b, sqrt(a**2 + b**2)])
combinations
只是itertools
模块的功能,您可以在此处阅读。
正如下面的评论中指出的那样,有一种方法可以进一步简化它。
0 = 1000 2 - 2000a - 2000b - 2ab
可以改写给予b
来讲a
。
a = 1000 * 500-b / 1000-a
combinations(range(1,1000), 2)
将给出一百万个条目的列表。 它按n 2
缩放。 通过编写b
来讲a
,也是唯一遍历range(1,1000)
一次,你把它降低到O(N),从O( n 2
)。
相反,您可以执行以下操作:
from math import sqrt, floor
for a in range(1, 500):
b = 1000 * (500-a) / (1000-a)
c = sqrt(a**2 + b**2)
if int(floor(c)) == c and 0 < a < b < c:
print a, b, c
如果需要,可以将c
为一个int
,但是如果它由于某种原因不起作用,则将其屏蔽。
def tripletSumsMyDValue(triplets):
for tri in triplets:
a,b,c = tri[0],tri[1],tri[2]
if d == int(a + b + c):
return tri
else:
return None
对于组中的每个三元组,如果有答案,则将其返回; 如果不是,则返回None
。 这意味着您永远不会在每个组中的第一个之后查看任何三元组。 答案出现在组150中,该组的三元组加起来为22952, 11704, 7956, 4960, 4212, 2968, 2720, 1980, 1736, 1400, 1260, 1040, 1000, 900, 880
; 因为22952
不是1000
,所以您使该组失败。
最简单的解决方法是删除整个else
子句。 如果您在循环期间从不return tri
,则将退出函数的结尾并默认返回None
。
但是,值得注意的是,即使进行了此修复,即使您确定很快就会达到无法再使用任何值的地步,您的代码也永远不会因没有答案的数字而终止。 (如果不仔细阅读,我不确定该点在哪里;也许inc > d
吗?)
作为附带说明,您可以大大简化此代码。 首先,如果tri
始终具有三个成员(确实如此),则以下等价:
a,b,c = tri[0],tri[1], tri[2]
a,b,c = tri
或者甚至可以for a,b,c in triplets:
做for a,b,c in triplets:
或者,甚至更简单:
for tri in triplets:
if d == int(sum(tri)):
return tri
由于c = 1000-a-b,因此也可以使用以下更短,更快的Python代码:
# i = a, k = b, j = c
for i in range (1 , 1000):
for k in range (i + 1 , 1000):
j = 1000 - i - k
if (i ** 2 + k ** 2 == j ** 2) & (i + j + k == 1000):
print (i * k * j)
break
您可以按照以下简单方式编写程序:
#function to find the pythagorean triplet
#Using Dickson formula
def pythagorean_triplet_dickson():
for r in range(1,1000):
for s in range(1,r):
if ((r**2)/2)%s == 0:
t = (r**2/2)/s
if r+s+r+t+r+t+s == 1000:
return (r+s)*(r+t)*(r+t+s)
#Printing the result
print pythagorean_triplet_dickson()
import time
start = time.time()
def isok():
for a in range(100,1000):
for b in range(100,1000):
for c in range(100,1000):
if a + b + c == 1000 and a ** 2 + b ** 2 == c **2:
print("a is {} b is {} c is {}".format(a,b,c))
print("anwser is",a * b * c)
return True
print(isok())
elapsed = (time.time() - start)
print("This code took: " + str(elapsed) + " seconds")
for i in range(1,500):
for j in range(1,500):
c = (i ** 2 + j ** 2) ** 0.5
if i+j+c ==1000:
print(i*j*c)`
我猜这是最短的代码。 我使用500是因为斜边必须大于其他边,并且简单的数学运算:D
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.