这段代码如何计算一组正整数的所有子集,其总和是偶数?

时间:2013-07-03 16:49:57

标签: algorithm sum subset

我在TopCoder解决方案中遇到了这段代码让我很困惑。有一个正偶数和奇数整数的数组列表。我认为它返回的总和是偶数模MOD的子集数。我相信MOD只是为了避免溢出,如果列表很大,所以如果你保持数字小于32,那么我认为你不需要它。

ArrayList l = { ... positive even and odd integers ... };

int dp[] = {1,0};
for (int i = 0; i < l.size(); ++i) {
        int even = dp[0];
        int odd = dp[1];
        if (l.get(i) % 2 == 0) {
                even *= 2;
                odd *= 2;
        } else {
                even += odd;
                odd = even;
        }
        dp[0] = even % MOD;
        dp[1] = odd % MOD;
}
return (dp[0] - 1 + MOD) % MOD;

如果所有整数都是偶数,那么我认为答案是2 ^ N-1。 但似乎至少有一个奇数,答案变为2 ^(N-1)-1。是对的吗?如果是这样,为什么要跟踪偶数/奇数?

1 个答案:

答案 0 :(得分:4)

这根本不需要迭代程序。假设你的集合有N个元素,k even和N-k odd。那么,k偶数并不是真正相关的;它们的2 ^ k个组合中的任何一个,以及具有偶数和的奇数的子集,组合成偶数和。

奇数的组合有多少甚至总和?如果N-k> 0,它们有2 ^(N - k - 1)。所以,你是对的。这是一个编码问题而不是数学问题。

但是给定的算法如下:

当N = 0时,集合中只有一个子集:空集合,总和为0.因此,从even=1odd=0开始。现在归纳步骤:假设前k个元素的分区数是evenodd

如果第k + 1个数是偶数,则其和为偶数的第一个k的任何子集可以附加(或不附加)第k + 1个元素,使偶数子集的数量加倍。这同样适用于具有奇数和的子集。

如果第k + 1个数是奇数,那么其和为偶数的前k个数的任何子集都不会给出具有第k + 1个数的任何新的偶数子集,而第一个k的一个子集如果附加第k + 1个,则和为奇数的数字给出一个具有偶数和的数字。因此,新even是旧evenodd的总和。同样,新的odd也是相同的总和,因此新的odd等于新的even

注意所有k的even + odd == 2^k,无论如何。并且,一旦有一个奇数,该指数even == odd并且全部更高。