如何找到2到1000之间的数字子集,在子集中任何两个数字不共享公共素数因子(例如,1000和500共享素数因子)的条件下,将为您提供最大总和2)?
上述问题的一个(可能更容易)变化:子集中最大的数字是多少?我们知道997是素数,并且很容易排除1000和998,因此问题变成子集中是否为999?
答案 0 :(得分:4)
创建一个包含节点{2,...,1000}的图形,以及当节点具有gcd>时的边缘。 1.解决这个问题的方法与查找maximum-weight independent set problem相同,除了某些特殊情况外,它是NP难的。这个图表案例看起来不像维基百科页面上的列表中的空间案例,甚至不是list。
<强>更新强>
正如詹姆斯所说,可以减少该图中的节点数量。假设使用素数分解p1^k1*...*pn^kn
的数字N的签名是元组(p1, ..., pn)
。
首先,当存在具有较大值和相同签名的节点时,删除节点。这将图表减少到607个节点。
如果存在签名分解为N
且sum为(p1, ..., pn)
的节点,则下一步缩减是删除带有签名(p1, ..., pn)
的节点>= N
。这将图形缩减为277个节点。
从这些节点73是孤立的节点(素数> 500。)
答案 1 :(得分:2)
我不知道答案,这对我来说似乎并非无足轻重。这里有一些想法。
总和由可变数量的加数组成,比如s 0 + s 1 + ... s k ,其中s < sub> i 是区间[2,1000]中的整数。现在每个s i 都有一个素数因子分解s i =(p 1 e1 )*(p < sub> 2 e2 )...其中e i ≥1。
来自该子集的任何两个数字不共享公共素因子的条件&#34;相当于声明s i 是成对相对素数,即对于i≠j,gcd(s i ,s j )= 1。同样地,只要一个summand s i 包含一个素数p,这意味着没有其他的summand可能包含该素数。
那么如何将素数排列成加数?一个简单的规则是显而易见的。 [500,1000]中的所有素数只能作为单独的加数出现在总和中。如果它们乘以其他任何东西,即使是最小的素数2,产品也会太大。这样就完成了安排较小素数的任务。而且我不知道他们最好的方法。为了完整起见,我将提供以下显示单向的短python程序。
def sieve_prime_set(n):
# sieve[i] = set(p1, p2, ...pn) for each prime p_i that divides i.
sieve = [set() for i in range(n + 1)]
primes = []
next_prime = 1
while True:
# find the next prime
for i in range(next_prime + 1, len(sieve)):
if not sieve[i]:
next_prime = i
break
else:
break
primes.append(next_prime)
# sieve out by this prime
for kp in range(next_prime, n + 1, next_prime):
sieve[kp].add(next_prime)
return sieve, primes
def max_sum_strategy1(sieve):
last = len(sieve) - 1
summands = [last]
max_sum = last
prime_set = sieve[last]
while last >= 2:
last -= 1
if not sieve[last] & prime_set:
max_sum += last
prime_set |= sieve[last]
summands.append(last)
return max_sum, summands, prime_set
def max_sum_strategy2(primes, n):
return sum(p ** int(log(n, p)) for p in primes)
if __name__ == '__main__':
sieve, primes = sieve_prime_set(1000)
max_sum, _, _ = max_sum_strategy1(sieve)
print(max_sum)
print(max_sum_strategy2(primes, 1000))
输出
84972
81447
显示&#34;策略1&#34;是优越的。
优越,但不一定是最佳的。例如,包括1000似乎很好,但它迫使我们排除每个其他甚至summand和每个可被5整除的summand。如果我们留下1000但是包括998,我们可以使用另一个包含5的其他summand&#39; s素数分解。但包括998强迫其他命令被排除在外。因此,最大化总和并非易事。
答案 2 :(得分:1)
这是解决问题的 Python 脚本。在我的笔记本电脑上运行需要几分钟时间。
import math
import networkx as nx
max_number = 1000
G = nx.Graph()
for i in range(2, max_number + 1):
G.add_node(i, weight=i)
for i in range(2, max_number + 1):
for j in range(i+1, max_number + 1):
if math.gcd(i, j) == 1:
G.add_edge(i, j)
numbers, sum_of_numbers = nx.max_weight_clique(G)
print(sorted(numbers))
print(sum_of_numbers)
返回的数字列表如下所示;总数是 85684。(可能还有其他有效的数字集可以给出这个总数。)
[41, 59, 67, 71, 79, 83, 97, 101, 103, 107, 113, 127, 131, 137, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 841, 853, 857, 859, 863, 877, 881, 883, 887, 893, 901, 907, 911, 919, 925, 929, 937, 941, 947, 949, 953, 961, 967, 971, 973, 976, 977, 979, 981, 983, 989, 991, 997]