【问题标题】:Subset sum variant with modulo带模的子集和变体
【发布时间】:2018-06-02 04:37:10
【问题描述】:

给定一个整数数组 A 和整数 N, M。我想找到 A 的所有子集 S,其中 (sum(S) mod M = N)。 A 可以有多个相同值的整数。 在我的例子中,N 将在 0

有什么好的/“快速”的方法可以做到这一点吗?

谢谢!

【问题讨论】:

  • 编写一些代码并对其进行基准测试。

标签: algorithm dynamic-programming subset-sum


【解决方案1】:

如果您只想计算它们,我们可以在O(|A| * M) 中使用动态规划解决它。这是一个例子:

A = [2, 6, 4, 3]
M = 5

    0 1 2 3 4
S = 0 0 0 0 0 // The number of subsets with sum i (mod M)

// Iterate over A (through S each time)
2   0 0 1 0 0
6   0 1 1 1 0
4   1 2 2 1 1
3   3 3 3 3 3

Python 代码:

A = [2, 6, 4, 3]
M = 5
S = [0 for i in range(0, M)]


for a in A:
  STemp = [0 for i in range(0, M)]
  for (i, v) in enumerate(S):
    ii = (a + i) % M
    STemp[ii] = S[ii] + v
  STemp[a % M] = STemp[a % M] + 1
  S = STemp
  
print(S)  # [3, 3, 3, 3, 3]

【讨论】:

  • 嘿!我真的不知道目标总和(N)来自哪里。你也能解释一下你制作的表格吗,真的不明白它在说什么以及你能从中读到什么。谢谢!
  • @AntonAndell 感谢您查看。这是一种计算有多少子集的总和为 i 模 M 的解决方案,其中 i 的范围从 0M-1。因此,总和 NM 的子集计数将包含在最终数组中。该表实际上是在处理A 中的下一个元素时更新的一行。
  • @AntonAndell 正如我所指出的,行中的每个索引都表示“总和 index (mod M) 的子集数。”你能想到如何将下一个元素应用到上一行吗?如果您需要这方面的帮助,请告诉我。这里有一个提示:问问自己,“对于S[i] 中表示的每个子集,可以使用下一个元素生成多少个子集,A 中的a,该计数将放在哪里?”考虑到如果我们将 a 添加到任何此类子集,我们将知道其结果 mod M
  • 谢谢,它更清楚了。但是我正在尝试获取特定的子集,您认为我可以扩展这种方式来跟踪子集吗?
  • @AntonAndell 我相信,如果我们保存完整的|A|*M 表(而不是覆盖单行),我们可以向后工作以适当地聚合仅对子集和N 有贡献的整数模M。不过,实现它可能并非易事,但复杂性应该只增加列出实际子集所需的时间和空间。
【解决方案2】:

在 O(2n/2 log2(2n/2)) = O(2 n/2 (n/2)),在你的约束下,这在 C++ 上的工作时间不到一秒。

你只需要:

1) 计算数组的第一个 n/2 元素的所有可能总和,并将它们放入 map<int, int> left 其中 left[sum] = 总和出现在数组左侧的次数

2) 计算数组最后一个 n/2 元素的所有可能总和,并且对于每个总和 S 检查是否映射 left 包含值 (N - S + M)%M

要查找所有可能的总和,您可以使用位掩码:

for (int mask = 1; mask < pow(2, n/2); mask++) {
    int sum = 0;
    for (int i = 0; i < n/2; i++)
        if ( (int) (mask & (1<<i)) ) 
            sum += A[i];
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-23
    • 1970-01-01
    • 2015-12-24
    相关资源
    最近更新 更多