生成一组子集 - Distinct-Sum整数的算法

时间:2014-09-22 15:23:03

标签: algorithm combinatorics subset-sum

我试图为纸牌游戏创建一个评分系统,通过设置每张牌的点值,使得两张牌的组合不能加起来相同的得分,从而排除得分的关系。 (对于这种特殊情况,我需要一组17个整数,因为有17张可评分卡。)

我已经尝试了几种启发式方法(沿着采用整数数组,迭代生成随机子集,并丢弃出现在共享一个公共和的子集中的那些方法的各种风选程序);然后详尽地验证结果(通过枚举它们的子集)。

从我所看到的,这个集合的大小的理论极限接近log2(n),其中n是从中绘制子集 - distinct-sum子集的超集成员的数量。然而,虽然我已经能够接近这一点,但我还是无法与之匹敌。到目前为止,我最好的结果是一组13个整数,从10,000到25,000,000之间的250,000个整数中抽取,数到数百(后者对算法来说无关紧要,但是我的用例是一个域约束):

[332600,708900,2130500,2435900,5322500,7564200,10594500,12776200,17326700,17925700,22004400,23334700,24764900]

我一直在寻找,而且大多数SDS发生器都是序列生成器,它们不假装创建密集集合,而是能够无限期地继续使用更大和更大的数字(例如Conway-Guy序列) )。我没有这样的约束,并且更喜欢更密集的集合而不需要彼此的序列关系。

(我确实考虑过使用Conway-Guy序列n = 2..18 * 10,000,但结果集的范围比我想要的更广。我也非常喜欢更通用的算法。)< / p>

编辑:为了清楚起见,我正在寻找一种方法(非确定性或动态编程方法很好),以生成比简单枚举指数或使用像Conway-Guy这样的序列所提供的密度更大的SDS集。 。我希望通过丢弃&#34;序列生成器&#34;约束,我可以找到比这些序列更接近的数字。

2 个答案:

答案 0 :(得分:1)

对于N的任何值,很容易生成最多Floor(Log2(N))-1个数字(我们称之为&#34; S&#34;),以便:

  1. S的所有成员都小于或等于N,

  2. 没有两个不同的S子集具有相同的总和,

  3. S的所有成员都是彼此的两倍。

  4. 你的怀疑是正确的,因为S在任何意义上都不是可扩展的(你不能添加更多的成员)

    方法:

    1. 对于N,找到T = 2^P,其中T是2的最大幂,小于或等于N.即:

      • P = Floor( Log2(N) )
      • T = 2^P
    2. 然后可以将S的成员生成为:

      • for( i=0 to P-2 ): S(i) = 2^i + 2^(P-1)
      • 或者换句话说,S(i) = 2^i, for 0<= i < P-1
    3. 这使得总共有P-1(或Floor(Log2(N))-1)成员。 S的两个不同子集可以相加到相同的数字吗?号:

      证明

      让我们考虑S:U和V的任何两个子集,它们是不同的(也就是说,它们没有共同的成员)。然后U的总和是:

      Sum(U) = O(U)*(T/2) + Sum(2^i| S(i):U)
      

      其中

      • O(U)是集合U的顺序(它有多少元素),
      • &#34; S(i):U&#34;表示&#34; S(i)是U &#34;和
      • 的元素
      • &#34; |&#34;是调节操作员(意思是&#34;鉴于......&#34;或&#34;其中......&#34;),

      所以,将最后两个放在一起,Sum(2^i| S(i):U)只意味着&#34; 两个属于U &#34;的所有权力的总和。 (记住S(i) = 2^i))。

      同样,V的总和是:

      Sum(V) = O(V)*(2^(P-1)) + Sum(2^i| S(i):V)
      

      现在因为U和V是截然不同的:Sum(2^i| S(i):U)永远不能相等,因为两个不同的两个幂的总和不能相等。

      另外,因为Sum(2^i; 0 <= i < P-1) = 2^(P-1)-1),这两个权力的总和必须始终小于2^P-1。这意味着如果出现以下情况,U和V的总和可能相等:

      O(U)*(2^(P-1)) = O(V)*(2^(P-1))
      

      O(U) = O(V)
      

      也就是说,如果U和V具有相同数量的元素,那么第一个术语将是相等的(因为第二个术语永远不会像第一个术语中的任何差异一样大)。

      在这种情况下(O(U) = (O(V)),第一项是相等的,因此Sum(U)等于Sum(V)IFF,它们的第二项(二进制和)也相等。但是,我们已经知道它们永远不会是平等的,因此Sum(U) = Sum(V)永远不会是真的。

答案 1 :(得分:0)

似乎另一种表达问题的方法是确保之前的术语永远不会与当前术语相加。如果情况绝非如此,那么你将永远不会有两笔相加的金额。

例如:2, 3, 6, 12, 24, 48, 96, ...

对任何单个元素{i}进行求和比先前项的总和多1个,并且对任何多元素集{i,j}的求和需要比以前元素的总和更多i以及之前j的元素。

更多数学:(i-1), i, 2i, 4i, 8i, ... 2^n i适用于任何i,n。

这种方法不起作用的唯一方法是,如果允许您在子集中选择两次相同的数字(如果是这种情况,则应在问题中指定它)。但是,这会导致Sum {i} = Sum {i}对任何数字的问题,因此这似乎是一个问题。