找到最大子集

时间:2011-03-22 15:35:32

标签: algorithm math

对于给定的n,找到{1,2,...,n}的子集S,使其

  1. S的所有元素都是互质的
  2. S的元素总和尽可能大
  3. 进行暴力搜索需要太长时间,我找不到模式。我知道我可以把所有的素数从1到n,但这可能不是正确的答案。感谢。

5 个答案:

答案 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).