【问题标题】:arrangement with constraint on the sum限制总和的安排
【发布时间】:2014-03-03 17:37:14
【问题描述】:

我正在寻找一种算法,该算法在所有组合的总和为 k,ka 为正的约束下,给出给定步骤 S(可以是正实数)的 n 个序列的重复排列整数。

因此,我的问题是找到方程的解:

x 1 + x 2 +⋯ + x n = k 在哪里

0 ≤ x i ≤ b i 和 S(步骤)是一个有限小数的实数。

例如,如果 0≤xi≤50,且 S=2.5,则 xi = {0, 2.5 , 5,..., 47.5, 50}。

这里的重点是仅查看 sum=k 的组合,因为如果 n 很大,则不可能生成所有排列,因此我想绕过它以仅生成与约束匹配的组合。

例如,我想从 n=2 开始,然后找到所有符合约束条件的线性组合。

例如:如果 xi = {0, 2.5 , 5,..., 47.5, 50} 并且 k=100,那么我们只有一个组合 ={50,50} 对于 n=3,我们有 n=2 乘以 3 的组合,即 {50,50,0}、{50,0,50} 和 {0,50,50} 加上组合 {50,47.5,2.5} * 3!等等……

如果 xi = {0, 2.5 , 5,..., 37.5, 40} 和 k=100,那么我们有 0 个组合用于 n=2,因为 2*40

我有点迷茫,因为我知道我应该将步骤 S 和 b 作为输入,我似乎无法找到启动算法的正确方法。

你有什么建议吗?

谢谢

【问题讨论】:

  • x_i 总是 0 和 x_{i+1} = x_i + S?老实说,我不太明白这个问题,也许你应该澄清一下
  • 或者更好的问题是:S是什么意思?
  • 为了让它不那么繁琐,我们假设 x_i 从 0 开始,实际上 x_{i+1} = x_i + S。S 是 x_i 序列中的步骤,但正如你所写的,我们确实可以得到通过将 x_i 序列除以步骤来摆脱步骤,以便只有 x_i' 是整数。如果 x_i= {0, 2.5 , 5,..., 47.5, 50} 那么 x_i'={0, 1 , 2,..., 19, 20}

标签: algorithm combinations


【解决方案1】:

您可以通过将所有内容除以 S 将您的问题转换为整数问题:我们想要找到所有整数序列 y1, ..., y n 与:

(1) 0 ≤ yi ≤ ⌊b / S⌋

(2) y1 + ... + yn = k / S

如果k不是S的倍数,我们可以看到没有解。一旦我们减少了问题,我建议使用伪多项式动态规划算法来解决subset sum problem,然后从中重建解决方案。令 f(i, j) 为将 ji 元素相加的方式数。我们有以下重复:

f(0,0) = 1
f(0,j) = 0  forall j > 0
f(i,j) = sum_{m = 0}^{min(floor(b / S), j)} f(i - 1, j - m)

我们可以在O(n * k / S)时间内通过逐行填充来解决f。现在我们要重建解决方案。我使用 Python 风格的伪代码来说明这个概念:

def reconstruct(i, j):
    if f(i,j) == 0: 
        return
    if i == 0:
        yield []
        return
    for m := 0 to min(floor(b / S), j):
        for rest in reconstruct(i - 1, j - m):
             yield [m] + rest

result = reconstruct(n, k / S)

result 将是所有可能组合的列表。

【讨论】:

  • 谢谢尼克拉斯。我不确定我得到 f(i,j) 的公式,尤其是 m 是什么?让我们举一个具体的例子:如果我取 y_i={0, 1 , 2,..., 19, b / S=20} 和 sum(y_i)=k / S = 100/2.5 = 40,那么对于 i= j=1 例如,我会得到 f(1,1) = sum(m=0)^min(20,1)*f(0,1-m) ? m是什么?此外,f(1,1) 是否表示用 1 个元素 i 求和 1 的方法数,i 是序列 y_i 的第一个元素,即 y_1=0?在这种情况下,f(1,1) 应该为 0,否则如果 i 是序列中的任何 1 个元素,则 f(1,1) 应该等于 1,它对应于 y_2=1
  • @Ouriel m 只是循环的迭代变量。我在这里使用了类似 LaTeX 的语法,它的意思是“从 m = 0 到 m = min(floor(b/S), j) 的总和”。 f(i,j) 是仅使用值 01、...、i 来求和 j 的方法数。
  • 嘿 Niklas,我对 b 0 和 k > b { f = f - f(n-1,kb-1,b) },因为如果 k>b 我需要从所有安排中删除,我包含两次的那些(包含-排除原则)。然而,当 n 很大时(n>=8)需要一些时间来计算。对于重建解决方案的部分,我不知道我们如何仅创建限制在 sum=k 上的解决方案,因为我们刚刚计算了获得 sum j 的方法的数量?对 Python 不是很熟悉。谢谢你的帮助:)
  • @Ouriel:计算应该不会花很长时间,n = 8 一点也不大。但是你必须小心使用dynamic programming 使用表格或记忆,这样你就不会重新计算结果。对于重建,您只需像回溯一样“执行”重复,如果您的 DP 数组表示当前分支没有解决方案,您只需修剪即可。例如,您查看(n,k),检查是否f(n,k) = 0。如果不是,则调用f(n,k-1) 并将k 附加到结果列表中。然后调用f(n-1,k) 并将k 附加到结果中
  • 当您说“您调用 f(n,k-1) 并将 k 附加到结果列表中”时。我实际上没有从我绘制的重复中得到任何列表。当我调用 f(n,k) 时,我唯一拥有的是满足以下条件的元素数量:每个元素的总和 = k,但我没有元素本身(这意味着我有许多所有组合但没有smthg like "(1,2,1)" for n=3, k=4 例如。那么我该如何创建这个结果列表呢?
【解决方案2】:

您所描述的内容听起来像是subset sum problem 的一个特例。一旦你把它放在这些术语中,你会发现 Pisinger 显然有一个linear time algorithm 来解决你的问题的更一般版本,因为你的权重是有界的。如果您对设计自己的算法感兴趣,可以先阅读Pisinger's thesis 以获得一些想法。

由于您正在寻找所有可能的解决方案,而不仅仅是单个解决方案,因此动态编程方法可能是您的最佳选择。

【讨论】:

  • 在 OPs 问题中,权重不受常数的限制。它们以 b 为界,这是问题实例的一部分
猜你喜欢
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
  • 2011-05-13
  • 1970-01-01
  • 2012-09-28
  • 2013-03-29
  • 1970-01-01
相关资源
最近更新 更多