对于给定的n,找到{1,2,...,n}的子集S,使其
进行暴力搜索需要太长时间,我找不到模式。我知道我可以把所有的素数从1到n,但这可能不是正确的答案。感谢。
答案 0 :(得分:4)
我会以dynamic programming problem来解决这个问题。让我走过它20。首先以相反的顺序取下素数。
19, 17, 13, 11, 7, 5, 3, 2
现在我们将走上最好的解决方案,这些解决方案使用了那些规模越来越大的素数的子集。我们将进行广度优先搜索的变化,但我们总是使用最大的当前未使用的素数(加上可能更多)。我将以size: {set} = (total, next_number)
的形式表示所有数据结构。 (我是手工完成的,所以所有错误都是我的。)以下是我们构建数据结构的方法。 (在每一步中,我都会考虑从上一步开始增加所有一组较小尺寸的方法,并采用最佳总数。)
尝试重现此列表,并以模拟我所犯的任何错误为准,你应该有一个算法。
Step 0
0: {} => (1, 1)
Step 1
1: {19} => (20, 19)
Step 2
2: {19, 17} => (37, 17)
Step 3
3: {19, 17, 13} => (50, 13)
Step 4
4: {19, 17, 13, 11} => (61, 11)
Step 5
5: {19, 17, 13, 11, 7} => (68, 7)
6: {19, 17, 13, 11, 7, 2} => (75, 14)
Step 6
6: {19, 17, 13, 11, 7, 5} => (73, 5)
{19, 17, 13, 11, 7, 2} => (75, 14)
7: {19, 17, 13, 11, 7, 5, 2} => (88, 20)
{19, 17, 13, 11, 7, 5, 3} => (83, 15)
Step 7
7: {19, 17, 13, 11, 7, 5, 2} => (88, 20)
{19, 17, 13, 11, 7, 5, 3} => (83, 15)
8: {19, 17, 13, 11, 7, 5, 3, 2} => (91, 18)
Step 8
8: {19, 17, 13, 11, 7, 5, 3, 2} => (99, 16)
现在我们只是向后追踪数据结构以读取16, 15, 7, 11, 13, 17, 19, 1
,我们可以对其进行排序1, 7, 11, 13, 15, 16, 17, 19
。
(注意有一个很多的细节,以便将其变成一个解决方案。祝你好运!)
答案 1 :(得分:3)
你可以通过掌握素数来做得更好,达到你的约束力。例如,假设n = 30。那么你想从
开始1, 16, 27, 25, 7, 11, 13, 17, 19, 23, 29
现在看看有哪些地方需要改进。当然你不能增加任何已经至少n / 2:17,19,23,29的素数(为什么?)。此外,3 ^ 3和5 ^ 2非常接近30,所以他们也可能最好独自留下(为什么?)。
但是2 ^ 4,7,11和13呢?我们可以取2并将它们与7,11或13组合。这样可以:
2 * 13 = 26 replaces 16 + 13 = 29 BAD
2 * 11 = 22 replaces 16 + 11 = 27 BAD
2^2 * 7 = 28 replaces 16 + 7 = 23 GOOD
所以看起来我们应该得到以下列表(现已排序):
1, 11, 13, 17, 19, 23, 25, 27, 28, 29
尝试证明这无法改进,这应该让您对一般情况有所了解。
祝你好运!答案 2 :(得分:1)
以下是非常实用的。
设N = {1,2,3,...,n}。 设p1< p2< p3< ......< PK是N的素数。 设Ti是N中可被pi整除的自然数,但不是任何小于pi的素数。 我们可以从每个子集Ti中选择最多一个数字。
现在递归。 S = {1}。 检查pi是否是S中已有的任何数字的除数。如果是,则跳过Ti。 否则,从Ti coprime中选择一个数字xi到已经存在于S中的元素,并将其添加到S. 转到下一个。
当我们达到k + 1时,计算S中元素的总和。如果是新的最大值,则将S保存。
继续。
取n = 30。 素数为2,3,5,7,11,13,17,19,23和29。
T1 = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}
T2 = {3, 9, 15, 21, 27}
T3 = {5, 25}
T4 = {7}
T5 = {11}
T6 = {13}
T7 = {17}
T8 = {19}
T9 = {23}
T10 = {29}
少于15 * 5 * 2 = 150种可能性。
这是我原来错误的结果,n = 100。
1 17 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 88 89 91 95 97 99
Sum = 1374
应该是
1 17 23 29 31 37 41 43 47 53 59 61 67 71 73 79 81 83 88 89 91 95 97
Sum = 1356
n = 150时不到2秒.n = 200时约为9秒。
答案 3 :(得分:0)
我认为这类似于subset problem,即NP-Complete。
首先,将每个数字分解为其素数因子(或使用素数列表生成从1到n的完整列表,同样的事情)。
通过查找不包含公共素数的子集来解决递归下降的子集问题。
运行所有解决方案并找到最大的解决方案。
答案 4 :(得分:0)
我在Prolog中实现了一个递归解决方案,基于按降序排列整数列表。在我相当古老的东芝笔记本电脑上,SWI-Prolog毫不犹豫地为N< 90.以下是N = 100到150乘以10的一些时间:
N Sum Time(s)
----- --------- -------
100 1356 1.9
110 1778 2.4
120 1962 4.2
130 2273 11.8
140 2692 16.3
150 2841 30.5
时序反映了对于每个N值从头开始的实现。如果N的结果先前已知,则可以跳过很多N + 1的计算,因此如果要计算值N的范围,利用这一点是有意义的。
Prolog源代码如下。
/*
Check if two positive integers are coprime
recursively via Euclid's division algorithm
*/
coprime(0,Z) :- !, Z = 1.
coprime(A,B) :-
C is B mod A,
coprime(C,A).
/*
Find the sublist of first argument that are
integers coprime to the second argument
*/
listCoprime([ ],_,[ ]).
listCoprime([H|T],X,L) :-
( coprime(H,X)
-> L = [H|M]
; L = M
),
listCoprime(T,X,M).
/*
Find the sublist of first argument of coprime
integers having the maximum possible sum
*/
sublistCoprimeMaxSum([ ],S,[ ],S).
sublistCoprimeMaxSum([H|T],A,L,S) :-
listCoprime(T,H,R),
B is A+H,
sublistCoprimeMaxSum(R,B,U,Z),
( T = R
-> ( L = [H|U], S = Z )
; ( sublistCoprimeMaxSum(T,A,V,W),
( W < Z
-> ( L = [H|U], S = Z )
; ( L = V, S = W )
)
)
).
/* Test utility to generate list N,..,1 */
list1toN(1,[1]).
list1toN(N,[N|L]) :-
N > 1,
M is N-1,
list1toN(M,L).
/* Test calling sublistCoprimeMaxSum/4 */
testCoprimeMaxSum(N,CoList,Sum) :-
list1toN(N,L),
sublistCoprimeMaxSum(L,0,CoList,Sum).