我想计算一组S的不相交子集S1和S2(S1 U S2可能不是S)存在多少对,其中S1中的元素之和= S2中元素的总和。
假设我已经计算了所有可能的2 ^ n子集的所有子集和。 我如何找到有多少不相交的子集具有相等的总和。
对于和值A,我们可以使用总和为A / 2的子集计数来解决这个问题吗?
举个例子: S = {1,2,3,4}
各种S1和S2设置可能是:
S1 = {1,2}且S2 = {3}
S1 = {1,3}且S2 = {4}
S1 = {1,4} nd S2 = {2,3}
以下是问题的链接: http://www.usaco.org/index.php?page=viewproblem2&cpid=139
答案 0 :(得分:1)
[编辑:修复了愚蠢的复杂性错误。谢谢kash!]
实际上我相信你需要使用 O(3 ^ n)算法described here来回答这个问题 - O(2 ^ n)分区算法只是好的足以枚举所有不相交的子集,其联合是整个地面集。
正如我所链接的答案所述,对于每个元素,您基本上决定是否:
考虑到每种可能的方法都会生成一个树,其中每个顶点有3个子节点:因此O(3 ^ n)时间。需要注意的一点是,如果您生成一个解决方案(S1,S2),那么您也不应该计算解决方案(S2,S1):这可以通过在构建它们时始终保持两组之间的不对称来实现,例如:强制S1中的最小元素必须始终小于S2中的最小元素。 (这种不对称执行具有将执行时间减半的良好副作用:))
如果您希望集合中有许多小数字,则可以使用另一种可能的加速:首先,按递增顺序对列表中的所有数字进行排序。选择一些最大值m,越大越好,但足够小,你可以买得起一个m大小的整数数组。我们现在将数字列表分成两部分,我们将分别处理:最初总和为m的数字的初始列表(此列表可能非常小),其余部分。假设第一个k <= n个数字适合第一个列表,并调用该第一个列表Sk。原始列表的其余部分我们将称为S'。
首先,将整数的size-m数组d[]
初始化为全0,并像往常一样解决Sk的问题 - 但不是仅记录具有相等和的不相交子集的数量,而是增加{{1对于每个对的不相交子集Sk1和Sk2,由这些前k个数组成。 (同时增加d[abs(|Sk1| - |Sk2|)]
以计算Sk1 = Sk2 = d[0]
时的情况。)想法是在第一阶段结束后,{}
将记录2个不相交子集的方式数可以从S的前k个元素生成具有d[i]
的差异。
其次,像往常一样处理余数(S') - 但不是仅记录具有相等总和的不相交子集的数量,而是每当i
时,将|S1'| - |S2'| <= m
添加到解决方案的总数中。这是因为我们知道有很多种方法可以从具有这种差异的前k个元素构建一对不相交的子集 - 对于这些子集对d[abs(|S1'| - |S2'|)]
中的每一个,我们可以添加较小的Sk1或Sk2 S1'或S2'中的较大者,另一个中的另一个,用一对具有相等和的不相交子集结束。
答案 1 :(得分:0)
这是一个clojure解决方案。
它将s定义为1,2,3,4的集合 然后将所有子集定义为所有大小为1 - 3
的集合的列表一旦定义了所有子集,它就会查看所有子集对,并仅选择不相等的对,不与原始集合并且其总和相等
(require 'clojure.set)
(use 'clojure.math.combinatorics)
(def s #{1, 2, 3, 4})
(def subsets (mapcat #(combinations s %) (take 3 (iterate inc 1))))
(for [x all-subsets y all-subsets
:when (and (= (reduce + x) (reduce + y))
(not= s (clojure.set/union (set x) (set y)))
(not= x y))]
[x y])
产生以下内容:
([(3) (1 2)] [(4) (1 3)] [(1 2) (3)] [(1 3) (4)])