计算小于或等于N的两个数字的对数,以使对数的数字总和为质数

时间:2019-05-08 05:22:59

标签: java algorithm primes discrete-mathematics number-theory

给出一个数字N,对所有对(X,Y)进行计数,以使X和Y的位数之和为质数。条件如下。

  • 1 <= N <= 10 ^ 50
  • 0 <= X,Y <= N
  • (X,Y)和(Y,X)是同一对。

我可以想到暴力破解方法。在其中,我需要放置两个从1到N的循环,并计算每个x和y对的数字总和,并检查其素数。但是它不是最佳解决方案,因为N的范围是10 ^ 50。

2 个答案:

答案 0 :(得分:1)

我一直在为此努力-我花了几次尝试才了解问题所在。我想写下自己在放弃之前学到的东西,然后转向更轻松的东西!

首先,我对@shiva解决方案的改进,该解决方案可以更快地产生正确的输出:

import sys
from functools import lru_cache

def sum_of_digits(number):
    summation = 0

    while number > 0:
        summation += number % 10
        number //= 10

    return summation

@lru_cache()
def is_prime(number):
    if number < 2:
        return False

    if number % 2 == 0:
        return number == 2

    divisor = 3

    while divisor * divisor <= number:
        if number % divisor == 0:
            return False
        divisor += 2

    return True

maximum = int(sys.argv[1])

count = 0

for i in range(maximum + 1):
    sum_i = sum_of_digits(i)

    for j in range(i, maximum + 1):
        if is_prime(sum_i + sum_of_digits(j)):
            count += 1

print(count)

在下面,我将其用作速度和准确性的基准。

即使对于10 ^ 50,所需的素数也很小,可以/应该提前计算。生成的数字总和的数量也相对较小,可以存储/散列。我的解决方案将所有可能的数字总和从0散列到10 ^ N,并将每个总和的生成次数存储为值。然后,它对数字总和(关键字)执行一对嵌套循环,如果这些总和为质数,则将计数每个总和的计算方式乘积(即,将值相乘)。

import sys
from math import ceil
from collections import defaultdict

VERBOSE = False

def sum_of_digits(number):
    summation = 0

    while number:
        summation += number % 10
        number //= 10

    return summation

def sieve_primes(n): 
    sieve = [False, False] + [True] * (n - 1)

    divisor = 2

    while divisor * divisor <= n: 
        if sieve[divisor]: 
            for i in range(divisor * divisor, n + 1, divisor): 
                sieve[i] = False
        divisor += 1

    return [number for number in range(2, n + 1) if sieve[number]]

power = int(sys.argv[1])  # testing up to 10 ** power

maximum_sum_of_digits = 18 * power
primes_subset = sieve_primes(maximum_sum_of_digits)

sums_of_digits = defaultdict(int)
for i in range(10 ** power + 1):
    sums_of_digits[sum_of_digits(i)] += 1

if VERBOSE:
    print('maximum sum of digits:', maximum_sum_of_digits)
    print('maximum prime:', primes_subset[-1])
    print('number of primes:', len(primes_subset))
    print('digit sums cached', len(sums_of_digits))

primes_subset = set(primes_subset)

count = 0

for i in sums_of_digits:
    sum_i = sums_of_digits[i]

    for j in sums_of_digits:
        if i + j in primes_subset:
            count += sum_i * sums_of_digits[j]

print(ceil((count + 2) / 2))  # hack to help adjust between duples and no duples count; sigh

(打开VERBOSE标志以查看有关该问题的更多信息。)

不幸的是,这与问题说明相反,它同时计算了(X,Y)和(Y,X),因此在代码末尾有一个近似的修正技巧可以对此进行调整。 (请提出一个精确的修正!)我称我的结果为近似值,但它通常只低1或2。与@shiva的代码不同,此函数以10的幂作为参数,因为它的目标是查看接近10 ^ 50可以得到。

  

很高兴看到N = 10 ^ 50(或至少10 ^ 8)– MBo的结果

        @Shiva reworked            My Attempt
          exact    secs        approx    secs
10^1         24    0.03            24    0.03
10^2       1544    0.04          1544    0.04
10^3     125030    0.49        125029    0.04
10^4   12396120   51.98      12396119    0.05
10^5 1186605815 6223.28    1186605813    0.14
10^6                     113305753201    1.15
10^7                   11465095351914   12.36
10^8                 1120740901676507  137.37
10^9               105887235290733264 1626.87

@shiva经过改进的解决方案在10 ^ 4以上无效,而我的沼泽在10 ^ 8以上下降。因此,达到10 ^ 50将会采取另一种方法。我希望其中一些代码和分析将有助于实现这一目标。

答案 1 :(得分:0)

尝试以下python代码并进行调试:

def sumofdigits(num):
  sum=0
  while num>0:
    sum+=num%10
    num=num//10
  return sum
def isprime(num):
  if num==0:
    return False
  i = 2
  while i<num:
    if num%i==0:
      return False
    i+=1
  return True
number = int(input("Enter number:"))
for i in range(0,number+1):
  for j in range(i,number+1):
    if isprime(sumofdigits(i)+sumofdigits(j)):
      print(i,j);

样本输出: enter image description here