如何找出哪个小计构成总和?

Posted

技术标签:

【中文标题】如何找出哪个小计构成总和?【英文标题】:How to find out which subtotal make up a sum? 【发布时间】:2013-07-26 09:39:46 【问题描述】:

我需要在一个列表中找到一个数字,这些数字构成了一个特定的总数:

Sum: 500

Subtotals: 10 490 20 5 5

In the end I need: 10 490, 490 5 5

您如何称呼这类问题?有没有算法可以有效地解决它?

【问题讨论】:

你试过了吗? 看起来像en.wikipedia.org/wiki/Subset_sum_problem。 我目前正在浏览这篇文章:en.wikipedia.org/wiki/Partition_(number_theory) 可以有负数吗? 【参考方案1】:

这是Knapsack problem,它是一个 NP 完全问题,即没有已知的有效算法。

【讨论】:

【参考方案2】:
    不是背包问题。 在最坏的情况下,有 N 个小计,可能有 O(2^N) 的解决方案,所以任何最坏情况下的算法都不会比这更好(因此,问题根本不属于 NP 类)。

假设 Subtotals 数组中没有非正数元素,并且任何元素都不大于 Sum。我们可以对小计数组进行排序,然后构建尾和数组,在末尾添加 0。在您的示例中,它将如下所示:

Subtotals:   (490, 20, 10,  5, 5)  
PartialSums: (530, 40, 20, 10, 5, 0)

现在对于任何“剩余总和”S、位置 i 和“当前列表”L,我们都有问题 E(S, i, L): E(0, i, L) = (打印 L)。 E(S, i, L) | (PartialSums[i] E(S, i, L) = E(S, i+1, L), E(S-Subtotals[i], j, L||Subtotals[i]),其中 j 是小计的第一个元素的索引大于或等于 (S-Subtotals[i]) 或 i+1,以较大者为准。 我们的问题是 E(Sum, 0, )。

当然,重复存在问题(如果您的列表中还有另外 490 个数字,此算法将输出 4 个解决方案)。如果这不是您需要的,使用对数组(值、多重性)可能会有所帮助。

P.S.如果问题的规模足够小,你也可以考虑动态规划:

    从集合 0 开始。创建大小等于小计数组的集合数组。 对于每个小计,通过添加小计值从以前的集合创建一个新集合。删除所有大于 Sum 的元素。将它与之前的集合合并(它本质上是所有可能总和的集合)。

    如果最终集合中没有 Sum,则无解。否则,您将解决方案从 Sum 回溯到 0,检查上一组是否包含 [value] 和 [value-subtotal]。 示例:

    (10, 490, 20, 5, 5)

套装:

(0)
(0, 10)
(0, 10, 490, 500)
(0, 10, 20, 30, 490, 500) (510, 520 - discarded)
(0, 5, 10, 15, 20, 25, 30, 35, 490, 495, 500)
(0, 5, 10, 15, 20, 25, 30, 35, 40, 490, 495, 500)

从上一组:[500-5]在上一组,[495-5]在上一组,[490-20]不在上一组([490]是),[490-490]是0,结果回答 5, 5, 490。

【讨论】:

我无法从根本上理解您的解决方案的作用,但我确信最初的问题是背包问题。对于原始列表中的 n 个元素,这些元素有 2n 个子集,您需要确定其总和正好是给定整数的那些子集。找到一个这样的子集已经很困难了。必须枚举所有这些问题并没有使问题变得更容易。 第一:背包问题需要两组数字、重量和成本。第二:背包问题是寻找是否存在适合背包的布局并且成本超过给定N。因此,背包问题的假设解决方案不能轻易转换为该问题的解决方案,它们是不同的问题。第三:背包问题是NP完全的,这意味着它与SAT问题“等价”。 Kiril 提出的问题是不是 NP,因为在最坏的情况下,它无法在多项式时间内解决(具有非多项式大小的输出)。 看看en.wikipedia.org/wiki/…。此处列出了权重等于成本的情况,并附注“如果每个项目的利润和权重相同,我们就会得到子集和问题”。子集问题也是 NP 完全的。是的,枚举任何可能具有指数倍数的问题的所有解决方案在 NP 中都不是问题。当我写“这是一个背包问题”时,我是在简化。我想我应该写成“决策版本已经是一个类似背包的 NP 完全问题,通常称为子集和”。 嗯,还是有一些区别的。首先,我们不想“尽可能接近”目标总和,我们想准确地达到它。其次,(大概)没有负数。在这些条件下,我看不到从问题中导出另一个 NP 完全问题的解决方案的明显方法(找到部分和的单个子集)。此外,背包问题是 NP 完全的,当且仅当 size 的背包容量是无限的(例如,它可以是 60 或 100 或 500 位长的数字)。否则,问题不是 NP 完全的,存在多项式解。

以上是关于如何找出哪个小计构成总和?的主要内容,如果未能解决你的问题,请参考以下文章

找出 TOP 10 函数的总和

如何找出为啥所有数据子集的总和比总和小1

多个组的 jQuery 数据表总和/小计

如何找出 Linux 中哪些进程正在使用交换空间?

如何高效地使用 SQL 检索半小时间隔的数据?

使用 VBA 的特定小计