再试: 100个约数1.578s, 150个约数67.7s!!
计划失败,怎么办呢,还是先分析下问题吧...
1. Array的读写吃了太多的时间
2. 太多没必要的计算...
没必要的计算?对,没必要的计算!
1. f(n-1) ~ f(n)之间的值的约数求解浪费了太多运算量
2. f(n) = n(n+1)/2,其实,我们是可以分成n*[(n+1)/2]或者(n/2)*(n+1)算的,把f(n)分成2部分的积,然后分别求解
例如f(8) = 8*9/2 = 4*9 = (2^2) * (3^2),即[2, 0] + [0, 2] = [2, 2]
结论?
1. 去除f(n-1) ~ f(n)之间的运算量,改回普通计算方式
2. 把f(n)分成2部分求解
代码见评论。
1. Array的读写吃了太多的时间
2. 太多没必要的计算...
没必要的计算?对,没必要的计算!
1. f(n-1) ~ f(n)之间的值的约数求解浪费了太多运算量
2. f(n) = n(n+1)/2,其实,我们是可以分成n*[(n+1)/2]或者(n/2)*(n+1)算的,把f(n)分成2部分的积,然后分别求解
例如f(8) = 8*9/2 = 4*9 = (2^2) * (3^2),即[2, 0] + [0, 2] = [2, 2]
结论?
1. 去除f(n-1) ~ f(n)之间的运算量,改回普通计算方式
2. 把f(n)分成2部分求解
代码见评论。
如前所料,速度果然大大提高,然而,与设想的却差了一大截:
50个约数需要0.437s,100个约数1.578s,150个约数67.7s!! 500个约数....依旧不敢想象...
50个约数需要0.437s,100个约数1.578s,150个约数67.7s!! 500个约数....依旧不敢想象...
---------------------------------
class Divisor
# prime_list: [2, 3, 5, 7, ...]
attr_accessor :primes
def initialize
@primes = Array.new(1, 2)
end
def n(num)
return 1 if (num == 1)
n = 2
n += 1 while num_of_divs(n) < num
return n
end
# number of divisors of f(n) = 1 + 2 + ... + n = n(n+1)/2
def num_of_divs(n)
if (n > 1)
cur = (n - 1) * n / 2 + 1
final = (n + 1) * n /2
while (cur < final)
add_prime(cur)
cur += 1
end
end
return num_of_divs_ex(n)
end
def add_prime(n)
sqrt = Math.sqrt(n).to_i
# already some primes
if (not @primes.empty?)
@primes.each do |prime|
break if (prime > sqrt)
return if (n % prime == 0)
end
end
@primes << n
end
# number of divisors of f(n) = 1 + 2 + ... + n = n(n+1)/2
def num_of_divs_ex(n)
n1 = n
n2 = n +1
sqrt = Math.sqrt(n2).to_i
if (n1 % 2 == 0)
n1 /= 2
else
n2 /= 2
end
count = 1
if (not @primes.empty?)
@primes.each do |prime|
break if (n1 == 1 && n2 == 1)
if (prime > sqrt)
count *= 2 if (not n1 == 1)
count *= 2 if (not n2 == 1)
break
end
tmp = 0
while (n1 % prime == 0)
tmp += 1
n1 /= prime
end
while (n2 % prime == 0)
tmp += 1
n2 /= prime
end
count *= (tmp + 1) if (tmp > 0)
end
end
return count
end
end
start = Time.now
div = Divisor.new
print '->' + div.n(50).to_s + '<-'
final = Time.now
cost =final - start
print 'Cost: ' + cost.to_s
# prime_list: [2, 3, 5, 7, ...]
attr_accessor :primes
def initialize
@primes = Array.new(1, 2)
end
def n(num)
return 1 if (num == 1)
n = 2
n += 1 while num_of_divs(n) < num
return n
end
# number of divisors of f(n) = 1 + 2 + ... + n = n(n+1)/2
def num_of_divs(n)
if (n > 1)
cur = (n - 1) * n / 2 + 1
final = (n + 1) * n /2
while (cur < final)
add_prime(cur)
cur += 1
end
end
return num_of_divs_ex(n)
end
def add_prime(n)
sqrt = Math.sqrt(n).to_i
# already some primes
if (not @primes.empty?)
@primes.each do |prime|
break if (prime > sqrt)
return if (n % prime == 0)
end
end
@primes << n
end
# number of divisors of f(n) = 1 + 2 + ... + n = n(n+1)/2
def num_of_divs_ex(n)
n1 = n
n2 = n +1
sqrt = Math.sqrt(n2).to_i
if (n1 % 2 == 0)
n1 /= 2
else
n2 /= 2
end
count = 1
if (not @primes.empty?)
@primes.each do |prime|
break if (n1 == 1 && n2 == 1)
if (prime > sqrt)
count *= 2 if (not n1 == 1)
count *= 2 if (not n2 == 1)
break
end
tmp = 0
while (n1 % prime == 0)
tmp += 1
n1 /= prime
end
while (n2 % prime == 0)
tmp += 1
n2 /= prime
end
count *= (tmp + 1) if (tmp > 0)
end
end
return count
end
end
start = Time.now
div = Divisor.new
print '->' + div.n(50).to_s + '<-'
final = Time.now
cost =final - start
print 'Cost: ' + cost.to_s
No comments:
Post a Comment