小编典典

子集和问题的这种变体更容易解决吗?

algorithm

我有一个与子集和问题有关的问题,我想知道这些差异是否使它更容易,即可以在合理的时间内解决。

给定一个值V,一个设置的大小L和一个数字序列[1,N] S,S的多少个大小L个子集的总和小于V?

这与子集和问题在三个方面不同:

  1. 我关心有多少子集 小于 给定值,而不是有多少 相等
  2. 子集大小是固定的。
  3. 我关心有 多少 集合的总和小于V,而不仅仅是是否存在任何集合。

有没有解决这个问题的合理有效的算法?

编辑:显然,这可以使用组合生成算法在O(N选择L)中完成。我真正感兴趣的是聪明的骇客,可以大大加快它的速度。


阅读 259

收藏
2020-07-28

共1个答案

小编典典

您的问题的(决策版本)仍然是NP完整的。这个想法是,如果我们能够解决您的问题,那么(对于每个子集大小)我们可以询问有多少集合的总和小于V,有多少集合的总和小于V-1,这两个数字之差将等于告诉我们子集是否恰好等于V-
因此我们可以解决子集总和问题。[这不是一个完整的证明,因为这是图灵的减少,不是很多减少。]

但是,有一个简单的 动态编程 解决方案可以在时间O(nLV)内运行。[这不能证明P =
NP的原因是V在输入大小上可能是指数的:使用n位,您最多可以表示2 n个值。但是假设您的V不是指数,这不是问题。]

令num [v] [k] [i]表示S的前i个元素的总和为k的大小为k的子集的数量。您可以将其计算为(对于每个i):

    num[0][0][i] = 1
    for v = 1 to V:
        for k = 1 to L:
            num[v][k][i] = num[v][k][i-1] + num[v-S[i]][k-1][i-1]

其中S [i]是序列中的第i个元素。(任何大小为k的总和等于v要么不使用S [i],所以将其计为num [v] [k] [i-1],或者使用S
[i],这意味着其余的该子集具有k-1个元素,仅使用序列中的前i-1个数字,并求和为vS [i]。)最后,对每个小于V的v计数num [v] [L] [|
S |] ; 那就是你的答案。

另外,如果您仔细地做的话,可以省略第三个下标(对每个i等向下循环)。我只是为了清楚起见包括了它。

2020-07-28