总体问题:项目Euler 12 - 第一个三角形数值超过500个除数的值是多少?
问题的焦点:除数函数
语言:Python
描述:我使用的函数是粗暴的,程序找到一个除数比x多的数字所需的时间几乎呈指数增长,每10或20个数字更高。我需要达到500或更多的除数。我已经确定了除数函数正在减少程序。我做的研究引导我去除除数函数,特别是 除数函数,它应该是一个函数,它将计算任何整数的所有除数。我看过的每一页似乎都是针对数学专业的,我只有高中数学。虽然我确实遇到过一些关于素数和阿特金斯筛选的页面,但是我无法在素数之间建立连接并找到任何整数的所有除数,也没有在网上找到关于它的任何东西。
主要问题:有人可以解释如何编码除数函数甚至提供样本吗?当我用代码查看它们时,数学概念对我来说更有意义。非常感谢。
强力除数函数:
def countdiv(a):
count = 0
for i in range(1,(a/2)+1):
if a % i == 0:
count += 1
return count + 1 # +1 to account for number itself as a divisor
答案 0 :(得分:5)
如果你需要一个暴力函数来计算除数(也称为tau(n))
这就是它的样子
def tau(n):
sqroot,t = int(n**0.5),0
for factor in range(1,sqroot+1):
if n % factor == 0:
t += 2 # both factor and N/factor
if sqroot*sqroot == n: t = t - 1 # if sqroot is a factor then we counted it twice, so subtract 1
return t
第二种方法涉及将n
分解为其主要因子(及其指数)。
tau(n) = (e1+1)(e2+1)....(em+1)
其中n = p1^e1 * p2^e2 .... pm^em
和p1,p2..pm are primes
更多信息here
第三种方法更容易理解,只需使用Sieve来计算tau
。
def sieve(N):
t = [0]*(N+1)
for factor in range(1,N+1):
for multiple in range(factor,N+1,factor):
t[multiple]+=1
return t[1:]
这是ideone
的实际操作答案 1 :(得分:4)
我同意此处提交的其他两个答案,您只需要搜索该号码的平方根。不过,我有一件事要补充一点。提供的解决方案将在合理的时间内为您提供正确的答案。但是当问题变得越来越困难时,你将需要一个更强大的功能。
看看Euler's Totient function。虽然它只是间接适用于此,但它在后来的问题中非常有用。另一个相关概念是Prime Factorization。
改进算法的一种快速方法是找到数字的素数因子分解。在维基百科文章中,他们使用36作为示例,其素数因子分解为2 ^ 2 * 3 ^ 2。因此,知道这一点,你可以使用组合数来找出36的因子数。这样,你实际上不会计算每个因子,而且你只需要在完成之前检查除数2和3。
答案 2 :(得分:1)
在搜索n
的除数时,您永远不必搜索数字n
的平方根。每当你发现一个小于sqrt(n)
的除数时,只有一个匹配除数大于根,所以你可以将count
增加2(如果你找到除数d
{ {1}}然后n
将成为对应方。)
注意方形数字。 :)当然,根将是一个不计数两次的除数。
答案 3 :(得分:0)
如果你要解决Project Euler问题,你需要一些处理素数和整数分解的函数。这是我的适度库,提供primes(n)
,is_prime(n)
和factors(n)
;重点是简单,清晰和简洁而牺牲速度,尽管这些功能应该足以让Project Euler:
def primes(n):
"""
list of primes not exceeding n in ascending
order; assumes n is an integer greater than
1; uses Sieve of Eratosthenes
"""
m = (n-1) // 2
b = [True] * m
i, p, ps = 0, 3, [2]
while p*p < n:
if b[i]:
ps.append(p)
j = 2*i*i + 6*i + 3
while j < m:
b[j] = False
j = j + 2*i + 3
i += 1; p += 2
while i < m:
if b[i]:
ps.append(p)
i += 1; p += 2
return ps
def is_prime(n):
"""
False if n is provably composite, else
True if n is probably prime; assumes n
is an integer greater than 1; uses
Miller-Rabin test on prime bases < 100
"""
ps = [2,3,5,7,11,13,17,19,23,29,31,37,41,
43,47,53,59,61,67,71,73,79,83,89,97]
def is_spsp(n, a):
d, s = n-1, 0
while d%2 == 0:
d /= 2; s += 1
if pow(a,d,n) == 1:
return True
for r in xrange(s):
if pow(a, d*pow(2,r), n) == n-1:
return True
return False
if n in ps: return True
for p in ps:
if not is_spsp(n,p):
return False
return True
def factors(n):
"""
list of prime factors of n in ascending
order; assumes n is an integer, may be
positive, zero or negative; uses Pollard's
rho algorithm with Floyd's cycle finder
"""
def gcd(a,b):
while b: a, b = b, a%b
return abs(a)
def facts(n,c,fs):
f = lambda(x): (x*x+c) % n
if is_prime(n): return fs+[n]
t, h, d = 2, 2, 1
while d == 1:
t = f(t); h = f(f(h))
d = gcd(t-h, n)
if d == n:
return facts(n, c+1, fs)
if is_prime(d):
return facts(n//d, c+1, fs+[d])
return facts(n, c+1, fs)
if -1 <= n <= 1: return [n]
if n < -1: return [-1] + factors(-n)
fs = []
while n%2 == 0:
n = n//2; fs = fs+[2]
if n == 1: return fs
return sorted(facts(n,1,fs))
一旦你知道如何计算一个数字,就很容易计算除数的数量。考虑76576500 = 2 ^ 2 * 3 ^ 2 * 5 ^ 3 * 7 ^ 1 * 11 ^ 1 * 13 ^ 1 * 17 ^ 1。忽略基数并查看指数,即2,2,3,1,1,1和1.为每个指数加1,给出3,3,4,2,2,2和2.现在相乘该列表获取原始数字76576500的除数数:3 * 3 * 4 * 2 * 2 * 2 * 2 = 576.这是函数:
def numdiv(n):
fs = factors(n)
f = fs.pop(0); d = 1; x = 2
while fs:
if f == fs[0]:
x += 1
else:
d *= x; x = 2
f = fs.pop(0)
return d * x
您可以在http://codepad.org/4j8qp60u处查看这些功能,并详细了解它们在my blog的工作原理。我会留给你解决问题12的解决方案。