繁体   English   中英

有效的方法来进行求和

[英]efficient methods to do summation

是否有任何有效的技术可以进行以下求和?

给定有限集A,其包含n个整数A = {X1,X2,...,Xn} ,其中Xi是整数。 现在 N个子集,由A1,A2,...,一个表示。 我们想要计算每个子集的总和。 有一些有效的技术吗?

(注意, n通常大于A的所有子集的平均大小。)

例如,如果A = {1,2,3,4,5,6,7,9}A1 = {1,3,4,5}A2 = {2,3,4} ,则A3 = .. 。 一种计算A1A2总和的简单方法需要5个Flops来添加:

总和(A1)= 1 + 3 + 4 + 5 = 13

总和(A2)= 2 + 3 + 4 = 9

...

现在,如果首先计算3 + 4,然后记录其结果7,我们只需要3个Flops进行添加:

总和(A1)= 1 + 7 + 5 = 13

总和(A2)= 2 + 7 = 9

...

广义案例怎么样? 有没有有效的方法来加速计算? 谢谢!

假设'addition'不仅仅是一个ADD操作,而是一些涉及两个整数操作数的非常密集的函数,那么一个明显的方法是缓存结果。

您可以通过合适的数据结构来实现这一点,例如包含由两个操作数组成的键的键值字典以及作为值的答案。

但是当你在问题中指定C时,最简单的方法是nn整数数组,其中x + y的解存储在array[x][y]

然后,您可以重复遍历子集,并为每对操作数检查数组中的适当位置。 如果没有值,则必须计算它并将其放入数组中。 然后,该值将替换子集中的两个操作数,并进行迭代。

如果操作是可交换的,则应在查找数组之前对操作数进行排序(即,使得第一个索引始终是两个操作数中的最小值),因为这将最大化“高速缓存”命中。

对于某些子集选择,有一些方法可以加快计算速度,如果你不介意做一些(可能很昂贵的)预计算,但并不是所有人都可以。 例如,假设您的子集是{1,2},{2,3},{3,4},{4,5},...,{n-1,n},{n,1}; 那么天真的方法每个子集使用一个算术运算,你显然不能做得更好。 另一方面,如果您的子集是{1},{1,2},{1,2,3},{1,2,3,4},...,{1,2,...,那么你可以用n-1算术运算得到,而天真的方法则要糟糕得多。

这是进行预计算的一种方法。 它并不总能找到最佳结果。 对于每对子集,将转换成本定义为min(对称差异的大小,Y-1的大小)。 (X和Y的对称差异是X或Y中的事物集合,但不是两者。)因此,转移成本是计算Y元素总和所需的算术运算数,给定总和X的。 将空集添加到子集列表中,并使用Edmonds算法(http://en.wikipedia.org/wiki/Edmonds%27_algorithm)或更快但更复杂的变体之一计算最小成本定向生成树那个主题。 现在确保当生成树有一个边X - > Y时,你在Y之前计算X.(这是一个“拓扑排序”,可以有效地完成。)

例如,当你有{1,2},{3,4},{1,2,3,4},{5,6},{7,8},{5,6时,这将给出明显不理想的结果,7,8}。 在使用上面的过程确定您的操作顺序之后,您可以执行优化过程,在这里您可以找到更便宜的方法来评估已经计算出的总和的每个集合的总和,这可能会在实践中给出相当不错的结果。

我怀疑,但没有试图证明,找到一组给定子集的最佳程序是NP难或更差。 (它当然是可计算的 ;你可能做的一组可能的计算是有限的。但是,从它的表面来看,它可能非常昂贵;可能你可能会跟踪大约2 ^ n个部分总和,添加任何一个它们在每个步骤中对任何其他步骤,并且具有高达大约n ^ 2步,对于超级天真的成本(2 ^ 2n)^(n ^ 2)= 2 ^(2n ^ 3)操作来尝试每种可能性。 )

常见的优化技术是预先计算中间结果。 在您的情况下,您可以使用A 2个加数预先计算所有总和,并将它们存储在查找表中。 这将导致|A|*|A+1|/2表条目,其中|A| A的基数。

为了计算Ai的元素总和,你:

  • 查找Ai的前两个元素的总和并将它们保存在tmp中
  • 在Ai中有一个元素x:
  • 查找tmp和x的总和

要从您的示例计算A1 = {1,3,4,5}的元素总和,请执行以下操作:

  • lookup(1,3)= 4
  • lookup(4,4)= 8
  • lookup(8,5)= 13

注意,计算任何给定Ai的总和不需要求和,因为在预先计算查找表时已经进行了所有工作。

如果将查找表存储在哈希表中,则lookup()位于O(1)中。


可能优化此方法:

  • 在计算求和结果的同时构造查找表; 因此,您只计算实际需要的那些总和。 您的查找表现在是一个缓存。
  • 如果您的加法操作是可交换的,则可以通过仅存储较小的加数首先出现的那些求和来节省一半的高速缓存大小。 然后修改lookup()使lookup(a,b) = lookup(b,a)如果a > b

如果假设求和是耗时的动作,你可以找到每对子集的LCS (通过假设它们按照注释中的提及进行排序,或者如果它们没有排序排序),之后计算最大长度的LCS总和(在所有LCS上)成对),然后用相关数字替换它在相关数组中的值,更新它们的LCS并继续这种方式,直到没有多个数字的LCS。 当然这不是最佳的,但它比天真的算法(总和的数量更少)更好。 但是,您可以进行回溯以找到最佳解决方案。

例如,您的样本输入:

A1={1,3,4,5} , A2={2,3,4}

LCS (A_1,A_2) = {3,4} ==>7 ==>replace it:

A1={1,5,7}, A2={2,7} ==> LCS = {7}, maximum LCS length is `1`, so calculate sums.

你仍然可以通过两个随机数的计算总和来改进它,然后再次采用LCS,......

没有。 没有高效的技术。

因为它是NP完全问题。 而这种问题没有有效的解决方案

为什么NP完全?
我们可以使用算法来解决集合覆盖问题 ,只需在集合中添加额外的集合,包含所有元素。

示例:我们有多组元素
A1 = {1,2},A2 = {2,3},A3 = {3,4}我们想解决集合覆盖问题。

我们添加到这个集合中,包含所有元素的数字集合A4 = {1,2,3,4}

我们使用约翰史密斯正在寻求的algorhitm,我们检查解决方案A4代表whit。 我们解决了NP-Complete问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM