我在一次结束的cp竞赛中发现了这个问题,因此可以解决。 如果(p1 + p2 + p3)除p1 * p2 * p3,则三个质数(p1,p2,p3)(不一定区分)称为特殊。如果素数不能超过10 ^ 6,我们必须找到这些特殊对的数量
我尝试了蛮力方法,但是超时了。还有其他方法吗?
答案 0 :(得分:1)
如果超时,则需要进行一些智能搜索来替换暴力破解。一百万以下还不到80,000素数,所以您超时就不足为奇了。
因此,您需要开始仔细看。
例如,其中p + 2也是素数的任何三元组(2,p,p + 2)都将满足以下条件:
还有其他以2开头的三元组吗?是否有以3开头的三元组?如果p1 = 3,p2和p3采取什么形式?将程序运行三倍(最多500个左右),然后在结果中查找模式。然后将这些结果外推到10 ^ 6。
我假定您正在使用筛子生成素数的初始列表。
答案 1 :(得分:1)
自您发布以来,我已经尝试过此问题。我还没有解决问题,但是想在介绍其他内容之前先传递我的见解:
生成素数是不是问题
使用适当的筛分算法,我们可以在几分之一秒内生成10 ** 6以下的所有素数。 (在我的Mac mini上不到1/3秒。)超出此时间优化素数生成的时间浪费了时间。
蛮力法
如果我们尝试在Python中生成三个素数的所有置换,例如:
for prime_1 in primes:
for prime_2 in primes:
if prime_2 < prime_1:
continue
for prime_3 in primes:
if prime_3 < prime_2:
continue
pass
或者更好的是,通过Python的itertools将问题降低到 C 级别:
from itertools import combinations_with_replacement
for prime_1, prime_2, prime_3 in combinations_with_replacement(primes, 3):
pass
然后,我们的计时,除了生成素数三元组外,不做任何实际工作,就像这样:
sec.
10**2 0.04
10**3 0.13
10**4 37.37
10**5 ?
您可以看到每个数量级增加多少时间。这是我的蛮力解决方案示例:
from itertools import combinations_with_replacement
def sieve_primes(n): # assumes n > 1
sieve = [False, False, True] + [True, False] * ((n - 1) // 2)
p = 3
while p * p <= n:
if sieve[p]:
for i in range(p * p, n + 1, p):
sieve[i] = False
p += 2
return [number for number, isPrime in enumerate(sieve) if isPrime]
primes = sieve_primes(10 ** 3)
print("Finished Sieve:", len(primes), "primes")
special = 0
for prime_1, prime_2, prime_3 in combinations_with_replacement(primes, 3):
if (prime_1 * prime_2 * prime_3) % (prime_1 + prime_2 + prime_3) == 0:
special += 1
print(special)
避免产生三元组,但仍然蛮力
这是一种避免生成三元组的方法。我们采用生成的最小和最大素数,将它们求立方,并使用 custom 分解函数遍历它们。此自定义因子功能仅返回由恰好三个素数组成的数字的值。对于由或多或少组成的任何数字,它将返回None
。这应该比正常分解更快,因为该函数可以尽早放弃。
容易精确检验构成三个素数的数字的特殊性。我们将假装我们的自定义因子分解功能完全不需要时间,只需测量一下我们花多长时间遍历所有有问题的数字即可:
smallest_factor, largest_factor = primes[0], primes[-1]
for number in range(smallest_factor**3, largest_factor**3):
pass
再次,一些时间安排:
sec.
10**2 0.14
10**3 122.39
10**4 ?
看起来并不乐观。实际上,这比我们最初的蛮力方法还差。实际上,我们的自定义分解功能会增加很多的时间。这是我关于此解决方案的示例(从上一示例中复制sieve_primes()
)
def factor_number(n, count):
size = 0
factors = []
for prime in primes:
while size < count and n % prime == 0:
factors.append(prime)
n //= prime
size += 1
if n == 1 or size == count:
break
if n > 1 or size < count:
return None
return factors
primes = sieve_primes(10 ** 3)
print("Finished Sieve:", len(primes), "primes")
special = 0
smallest_factor, largest_factor = primes[0], primes[-1]
for number in range(smallest_factor**3, largest_factor**3):
factors = factor_number(number, 3)
if factors:
if number % sum(factors) == 0:
special += 1
print(special)