【问题标题】:Modular Partitioning模块化分区
【发布时间】:2015-08-08 22:42:41
【问题描述】:

给定一个非负整数列表,比如 a0,a1,a2, . . . ,an 和一个常数正整数 m。我们想要生成所有形式为 a'0,a'1,a'2, 的非负整数列表。 . . ,a'n 使得:

  1. 存在一个 i 满足 ai ≠ a'i
  2. 对于所有 i,我们有 ai ≥ a'i
  3. a0 + a1 + a2 + 。 . . + an - a'0 - a'1 - a'2 - 。 . . - a'n 是 m 的倍数

就时间而言,什么是最好的java算法。我尝试了两种不同的方法。

  1. 对于介于 0 和 ais 之和之间的所有 km:首先将 km 的所有分区生成 n 个部分。对于这些分区中的每一个,从原始整数序列中逐个减去它。如果所有分量都是非负数,则结果列表有效。
  2. 生成所有较小的位置并检查它们是否满足条件 3。

令人惊讶的是,我的第二个想法比第一个想法快得多,但仍然相当慢。我应该如何处理这个?这个问题与Generating the partitions of a number的精神相似。

【问题讨论】:

  • 尝试在math.stackexchange.com 发帖,因为它看起来更像是数学问题而不是编程问题。
  • m 是谁?请完成您的问题
  • 只需选择ai = a'i for all i < na'n = an - m
  • 所以修复你的问题,这是你在问题中省略的第三个约束。 ai 也是正面的吗?否则如果一个ai 是负数是不可能的

标签: java algorithm performance numbers decomposition


【解决方案1】:

这可以使用动态规划在多项式时间内O(nm2)解决。

f (i, r) 为构建序列 a'0, a'1, .. ., a'i 这样

(a0 + a1, ... + ai - a'0 - a '1 - ... - a'i) mod m = r.

第一个参数的选择是显而易见的:我们将从左到右查看序列,并记录序列前缀的结果。 第二个参数是我们目前对 m 取模的余数,因为为了构建所有可能的序列,我们必须考虑其间所有可能的余数,而不仅仅是零。

要计算f (i, r),我们需要考虑(ai - a'i) 的可能选择mod m 并使用之前计算的 f (i - 1, *)

  • 如果 (ai - a'i) mod m = 0,则有 u = [ai / m] + 1 个这样的选择 a'i:这些是 ai, ai - m, a'i - 2 m, ..., a'i - u m。 因此,我们必须将 ([ai / m] + 1) * f (i - 1, r) 添加到我们的答案中:对于每个长度为 i - 1 且总余数为 r 的可能答案,我们可以选择 [ai / m em>] + 1 个可能的 a'i 值,使得新序列的总余数也是 r

  • 如果 (ai - a'i) mod m = m - 1,有 v = [(ai - 1) / m] + 1 这样的选择 a'i : 这些是 ai - 1, ai - 1 - m, a'i - 1 - 2 m, ..., a'i - 1 - v m。 所以,我们必须加上 ([(ai - 1) / m] + 1) * f (i - 1, (r + m - 1) mod m) 到我们的答案:对于长度为 i - 1 的每个可能的答案,总余数 (r + m - 1) mod m,我们可以选择 [(ai - 1) / m] + 1 个可能的 a'i 使得新序列的总余数现在是 r

  • ...

  • 如果 (ai - a'i) mod m = 1,则有 w = [(ai - (m - 1)) / m] + 1 个这样的选择 a'i sub>:这些是ai - (m - 1), ai - (m - 1) - m, a'i - (m - 1) - 2 m, ..., a'i - (m - 1) - w m。 所以,我们必须加上 ([(ai - (m - 1)) / m] + 1) * f ( i - 1, (r + 1) mod m) 得到我们的答案:对于长度为 i - 1 的每个可能答案,总余数 ( r + 1) mod m,我们可以选择 [(ai - (m - 1)) / m] + 1 个可能的 a'i 值,使得新序列的总余数现在是 r

    李>

总结一下,

f (i, r) = sum {by s = 0 to m - 1} of ([(a i - s) / m] + 1) * f (i - 1, (r + m - s) mod m) em>。

我们对所有 i 和所有 r 都这样做。 基数将是 f (-1, 0) = 1 (有一个空序列,总余数为 0)和 f (-1, t) = 0 对于 t > 0(不存在总余数 > 0 的空序列)。 答案将是 f (n, 0)(序列数 a'0, a'1, ..., a' i 余数为 0)。

在实现时,注意将整数除法四舍五入并取非负模:在接近 CPU 的语言中(如 C 或 C++ or even Java),整数除法和余数计算默认舍入为零,因此-1 / 2 的整数结果将是 0 和 -1 mod 2 将是 -1,当我们分别需要 -1 和 1 时。

【讨论】:

  • 非常感谢!这正是我想要的。
  • [n] 表示什么?
  • @Halbort [x] 是 x 舍入 向下 到最接近的整数。
猜你喜欢
  • 2020-03-08
  • 2013-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-28
  • 1970-01-01
相关资源
最近更新 更多