Algorithm 定义在子集上的函数之和

Algorithm 定义在子集上的函数之和,algorithm,time-complexity,Algorithm,Time Complexity,我想知道他们是否有解决以下问题的快速方法。我有一个成千上万的代码列表(A0,A1,A2,…)。大约一百万个不同的组合有一个正值(A0-A1,A2-A10,A1-A2-A10,…)。让这些值表示为f(A0-A1)。请注意,并非所有组合都附加了该值 对于列出的每个组合,我想计算附加到包含给定组合的每个集合的值的总和。例如,对于A2-A10, 算计 g(A2-A10) = f(A2-A10) + f(A1-A2-A10) + ... 我希望以最小的时间复杂性来完成这项工作。一个更简单的相关问题是找到

我想知道他们是否有解决以下问题的快速方法。我有一个成千上万的代码列表
(A0,A1,A2,…)
。大约一百万个不同的组合有一个正值
(A0-A1,A2-A10,A1-A2-A10,…)
。让这些值表示为
f(A0-A1)
。请注意,并非所有组合都附加了该值

对于列出的每个组合,我想计算附加到包含给定组合的每个集合的值的总和。例如,对于
A2-A10
, 算计

g(A2-A10) = f(A2-A10) + f(A1-A2-A10) + ...

我希望以最小的时间复杂性来完成这项工作。一个更简单的相关问题是找到
g(C)
大于阈值的所有组合。

使用位图对现有组合进行键控,其中bit
n
表示A
n
是否在该特定编码中。将位图为每个位图键入的值存储在您最喜欢的哈希映射结构中。因此,f(A0,A1,A10,A12)将是
组合值[11000000001010000…]

要对所有所需的组合求和,请构建根的位图。例如,使用上面的组合,我们将有
根=1100000000101000
(为了便于说明,将总共16个元素截断)

现在,使用
root
作为掩码,简单地循环遍历hashmap的键。求所需值的和:

total = 0
for key in combo_val.keys()
    if root && key == root
        total += combo_val[key]

这会让你行动起来吗?

我想在提出以下方法之前,时间太长了

为一百万个组合编制索引。这样您就知道需要哪一个。在您的示例中:

0: A0-A1
1: A2-A10
2: A1-A2-A10
A0: [0]
A1: [0, 2]
A2: [1, 2]
A10: [1, 2]
对于每个代码,创建包含该代码的有序组合列表。将其称为
code\u combs
。在您的示例中:

0: A0-A1
1: A2-A10
2: A1-A2-A10
A0: [0]
A1: [0, 2]
A2: [1, 2]
A10: [1, 2]
现在我们有了一组
代码
,如
A2-A10
。我们创建了两个数组,一个是代码,另一个是索引。将索引设置为0。因此:

codes = ['A2', 'A10']
indices = [0, 0]
现在请执行以下操作:

while not done:
    let max_comb = max(code_combs[codes[i]][indices[i]] over i in range(len(codes))
    Advance each index until we are at the max_comb or greater
        (if we reach the end of any list, we are done)
    If all are at the same max_comb, we add its value.
    Advance all indexes by 1.
        (if we reach the end of any list, we are done)
基本上,这是有序列表的k向交叉。现在是诀窍。如果我们天真地前进,这会稍微快一点,因为我们只需要查看包含代码的组合。但是,我们可以使用这样一种聪明的前进策略:

Advance by 1, 2, 4, 8, etc until we reach or pass the point we want.
Do a binary search between the last two values until we find the point we want
(请注意,实现二进制搜索并不总是那么容易做到正确。)


现在我们正在交叉手指。但是如果我们的任何一个代码中有几个组合,并且组合中没有太多的代码,我们可以非常快速地计算我们的交集。

可能是这样的吗?你可以构造一个偏序集,由所有附加正值的子集组成,按包含顺序排列。然后,想想它是一个lat从上到下,用一种dp方法计算超集值的累积和。人们仍然需要以某种方式跟踪包含排除。包含排除是我遇到的一个问题。可能有用,尽管它很难解决更一般的问题。@hilberts_契约。我们这里没有明确的DAG。我们可以在O(n^2*m)中构建一个“平坦”的DAG(等于它的传递闭包)(n是组合数,m是代码数)这难道不是一种有效的方法来循环所有百万条记录吗?是的,到目前为止。位图还允许更有效的索引,这取决于所使用的语言。蛮力迭代是…嗯,蛮力。我花了很长时间,但我想出了一些通常比蛮力更好的方法。