【发布时间】:2018-06-02 04:37:10
【问题描述】:
给定一个整数数组 A 和整数 N, M。我想找到 A 的所有子集 S,其中 (sum(S) mod M = N)。 A 可以有多个相同值的整数。 在我的例子中,N 将在 0
有什么好的/“快速”的方法可以做到这一点吗?
谢谢!
【问题讨论】:
-
编写一些代码并对其进行基准测试。
标签: algorithm dynamic-programming subset-sum
给定一个整数数组 A 和整数 N, M。我想找到 A 的所有子集 S,其中 (sum(S) mod M = N)。 A 可以有多个相同值的整数。 在我的例子中,N 将在 0
有什么好的/“快速”的方法可以做到这一点吗?
谢谢!
【问题讨论】:
标签: algorithm dynamic-programming subset-sum
如果您只想计算它们,我们可以在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]
【讨论】:
i 模 M 的解决方案,其中 i 的范围从 0 到 M-1。因此,总和 N 模 M 的子集计数将包含在最终数组中。该表实际上是在处理A 中的下一个元素时更新的一行。
index (mod M) 的子集数。”你能想到如何将下一个元素应用到上一行吗?如果您需要这方面的帮助,请告诉我。这里有一个提示:问问自己,“对于S[i] 中表示的每个子集,可以使用下一个元素生成多少个子集,A 中的a,该计数将放在哪里?”考虑到如果我们将 a 添加到任何此类子集,我们将知道其结果 mod M。
|A|*M 表(而不是覆盖单行),我们可以向后工作以适当地聚合仅对子集和N 有贡献的整数模M。不过,实现它可能并非易事,但复杂性应该只增加列出实际子集所需的时间和空间。
在 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];
}
【讨论】: