用于“求和”一组和的高效算法


24

给定自然数X的多集,请考虑所有可能总和的集合:

sums(X)={∑i∈Ai|A⊆X}

例如,而 。sums({1,5})={0,1,5,6}sums({1,1})={0,1,2}

计算逆运算最有效的算法是什么(以输入和的大小来衡量)?具体来说,可以有效地计算以下任何一项:

  1. 给定集是否为有效的和集。(例如,有效,而无效。){0,1,2}{0,1,3}
  2. 一个累加到给定集合的多重集。
  3. 在最小的多重集,总结到给定。(例如,和总和为但前者较小。){ 1 ,1 ,1 } { 0 ,1 ,2 ,3 }{1,2}{1,1,1}{0,1,2,3}

1
您能否给我们多个和集而不是和集?这将创建令人愉悦的对称性(请参见从多个值集开始)。
— DW

1
另一个问题-您对理论结果(例如渐近复杂性)或实际解决方案(在实践中可行的方案)最感兴趣吗?如果是后者,您是否对参数的典型值有所了解:例如,多集X的大小,多集X中最大元素的大小,最高多重性?这可能会影响应用像ILP求解器还是SAT求解器这样的“大锤子”是否合理。
— DW

@DW我绝对对使用和集而不是多重集感兴趣(尽管这可能也是一个有趣的问题)。另外,这最初是一个娱乐数学问题,所以我主要对复杂性范围感兴趣,而不是实际的解决方案。
— 乌里·格兰塔

3
如果给定了总和的多集,那么贪婪地进行此操作非常简单(请参见例如math.stackexchange.com/questions/201545/…)。
— jschnei

@UriZarfaty作为输入给出的集合已经排序?最后这是集合还是多集?评论仍然建议您要纯粹的设置。
— Evil

Answers:


9

解

解决方案包括两个部分。首先我们发现最小集,然后证明它可以表示幂和集。解决方案针对编程实现进行了调整。

最小集算法

  1. 从和(多)集合中找到最大元素。P,潜在的最小(多重)集最初为空。amP

  2. 除非只有一组,表示中的所有可能的方式为一对,加起来总和的一米,š 我Ĵ = { (一个我,一个Ĵ)| a i + a j = a m }amamSij={(ai,aj)|ai+aj=am}

  3. 检查是否包括总和中的所有元素。

  4. 查找最大元素的所有小号我Ĵ具有以下属性(合意):每个s ^ 我Ĵ,一个小号或者是在小号我Ĵ,或者我们可以找到一个p从集合资金,使一个p + a s在S i j中。asSijSijasSijapap+asSij

  5. 如果它是,该情况下不包含一个小号,只是总和一个小号 + 一个p,删除一个p + 一个小号从小号我Ĵ(或只设置一个标志忽略它),然后插入一个p和一个š在小号我Ĵ代替。Sijasas+apap+asSijapasSij

  6. 如果每个中都存在一个元素,则从所有S i j中将其删除一次(或仅设置一个标记以忽略该元素,不再触摸它)并将其添加到潜在最小集P的元素列表中。SijSijP

  7. 重复直到所有为空Sij

  8. 如果某些保持为非空并且我们无法继续,请尝试使用所有S i j中的最大值。SijSij

  9. 重新创建递归步骤而无需删除,并继续使用幂集覆盖算法。(在此之前,您可以进行安全检查,以确保P包含所有不能表示为两个元素之和的元素,因此确保它们必须位于基础集中。例如,最小元素必须位于P中。)PPP

(10.请注意,作为算法目标的最小集解不能包含多个相同数目的重复。)

例:

{2,3,5,7,8,10,12,13,15}

用所有可能的方式将15表示为总和中两个数字的总和。

(13,2),(12,3),(10,5),(8,7)

尝试找到所有组中或可以表示为和的最大数。显然,我们可以从8开始搜索。

第一组中的13是13 = 8 + 5,所以13是可以的,但是第二组中的12是不好的,因为在和集中没有4使12 = 8 + 4。接下来,我们尝试7。但是无法立即覆盖13,没有6。

接下来,我们尝试5。13 = 5 + 8、12 = 5 + 7、10 = 5 + 5,最后一个是8 = 5 + 3或7 = 5 + 2,但不能同时使用两者。现在的组是:

((5,8),2),((5,7),3),((5,5),5),((5,3),7)

5在所有组中重复,因此我们将其提取为。我们从每个组中仅提取5个。P={5}

(8,2),(7,3),(5,5),(3,7)

显然,没有点高于5,所以我们再次尝试5。8 = 5 + 3,7 = 5 + 2,所以一切都很好

((5,3),2),((5,2),3),(5,5),(3,(5,2))

从所有组中再次提取1至5,因为它在重复。(这是不常见的,但我们的情况是故意创建显示什么情况下,我们必须重复做。)P={5,5}

(3,2),(2,3),(5),(3,2)

现在我们尝试3并得到5 = 3 + 2。将其添加到组中。

(3,2),(2,3),(3,2),(3,2)

现在提取3和2,因为它们重复无处不在,我们是细和组是空的。P={5,5,3,2}

(),(),(),()

现在,我们需要不删除而重新创建递归步骤,这仅意味着执行上述操作而没有真正从删除元素,只需将它们放置在P中并标记不再更改即可。SijP

((5 ,8 ),2 ),((5 ,7 ),3 ),((5 ,5 ),5 ),((5 ,3 ),7

(13,2),(12,3),(10,5),(8,7)
((5 ,(5 ,3 )),2 ),((5 ,(5 ,2 )),3 ),((5 ,(3 ,2 )),5 ),((5 ,3 ),(5 ,2 ))
((5,8),2),((5,7),3),((5,5),5),((5,3),7)
((5,(5,3)),2),((5,(5,2)),3),((5,(3,2)),5),((5,3),(5,2))

动力装置覆盖

这部分的目的是检查找到的最小集合是否能够覆盖幂和集合。找到的解决方案有可能涵盖所有给定的总和,但它们不是幂集总和。(从技术上讲,您可以简单地从找到的最小集合中创建一个幂和集合,并检查每个和(如幂集合所指示的)是否在初始求和集合中。这就是所有与我们已经拥有的合并的东西,因此没有浪费。您可以在倒退递归时执行此部分。)

  1. 使用2的连续幂对最小值集中的所有元素进行编码。顺序并不重要。使用重复的新值对同一元素进行多次编码。从C = 1开始,每个下一个元素的C = 2C。

(2=[1],3=[2],5=[4],5=[8])
  1. 替换还原的递归列表中的元素,

((5,(5,3)),2),((5,(5,2)),3),((5,(3,2)),5),((5,3),(5,2))

编码:2与1、3与2、5与4,以及另外5与8。请注意,即使重复每个元素,其编码也不同。

((4,(8,2)),1),((4,(8,1)),2),((4,(2,1)),8),((8,2),(4,1))
  1. 收集所有中间和,目前我们有(1,2,4,8)

((4,(10)),1),((4,(9)),2),((4,(3)),8),((10),(5))

(1,2,3,4,5,8,9,10)

((14),1),((13),2),((7),8),(15)

(1,2,3,4,5,8,9,10,13,14,15)

{(15),(15),(15),(15)}
  1. 2m−1mm=4

  2. 收集从缺失数字12m−1

(6,7,11,12)

  1. 用以下方式证明其不存在:以二进制形式表示每个数字

(6=01102) (7=01112) (11=10112) (12=10102)

601102(2=[1],3=[2],5=[4],5=[8]){2,3,5,7,8,10,12,13,15},所以一切都很好。

701112(2=[1],3=[2],5=[4],5=[8])

1112

如果有任何二进制表示形式对应于找不到的总和,请报告没有解决方案。

(2,3,5,5)

讨论区

有必要提供一种算法,以检查总和是否覆盖了幂集完成,而幂集隐藏在二进制扩展中。例如,如果我们从初始示例中排除8和7,则第一部分仍将提供解决方案,只有第二部分将报告缺少的总和组合。

mnlog(m)mlog2⁡(m)mnlog⁡(m)

mlog⁡mmlog2⁡(m)

mlog3⁡(m)

该算法的某些部分假设我们可以在线性时间内找到一对和,因此需要进行排序。

启动错误

2,3,4,5,6,7,8,9,10,11,12,13,152,3,4,6Sij

5,4,3,3

2,2,3,4,42,3,4,6

一旦正确启动所有算法,此算法即可提供解决方案。

改进之处

步骤4.是可以这种方式升级的步骤:不是最大值,我们可以按满足给定条件的降序尝试每个元素。我们分别为每个分支创建一个分支。如果某个分支机构没有提供解决方案,请取消它。

2,3,4,5,6,7,8,9,10,11,12,13,157,6,5,4因为它们都通过了第一个测试,所以采用了不同的方式。(没有理由使用2或3,因为我们知道它们必须在基础集合中。)并一直以这种方式继续进行,直到我们收集所有可以到达末尾的版本为止。这将创建一个全覆盖解决方案,它将发现多个基础集。

另一件事,因为我们知道如果情况最小,我们最多只能重复一次,因此可以将其合并到我们的算法中。

总体而言,第4步中每个组都必须重复一个数字或具有创建总和的能力的条件足够强大,足以使我们脱离直接指数水域,这将是简单地尝试每种组合并产生幂的算法。设置每个,直到我们找到一个匹配。


1
更广泛地说:我看到了算法的文本描述,但是(a)没有伪代码,并且(b)没有正确性证明。您为什么认为此方法提供的算法可以在所有可能的输入上正常工作?有什么道理?您对此是否正确?
— DW

我认为问题共耗时约30个小时(每小时收费30倍,好吧……)。但是没有付费选择。

最后,详细阅读答案。做得好!
— Uri Granta

1

注意:一般而言,这不太有效,请参见下面的Uri反例。

YY

  • 0∈Y
  • yYyXY
  • z1<⋯<znYY′Y=Y′+{0,y}0Y′i=1,…,nzi+y∈YziY′zi−y∉Yzi+y∉Yzi+y∈YziY′
  • Y′y,y′,…

1yO(n)O(n2)

Y={0,1,3,4,5,6,7}{0,1,3,4,6}{0,1,3,5,6}y∈Y{a+k⋅y}YY′


Y'不会导致死胡同吗?毕竟可以有很多Y,使得Y = Y'+ {0,y}。例如{0,1,2,3,4} = {0,2,3} + {0,1} = {0,1,2,3} + {0,1},但前一种分解会导致死路。
— Uri Granta

没错,这是一个现实的问题。我必须看看它是否可以解决。谢谢!
— 克劳斯·德拉格

Y′kY=Y′+{0,y,…,y}{0,y,…,y}kyY′
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.