用于计算形成100的组合数的算法

时间:2010-08-18 09:20:04

标签: c# algorithm scala

我遇到了一个棘手的情况,我需要根据不同的因素来计算形成100的组合数。

那些是

  • 组合数量
  • 乘法因子
  • 距离

示例输入1:(2-10-20)

这意味着

  • 列出有效的双向组合以形成100.
  • 组合之间的距离应小于或等于20.
  • 并且所有结果组合必须能够被给定的乘法因子10
  • 整除

输出

  

[40,60]

     

[50,50]

     

[60,40]

此处[30,70],[20,60]无效,因为距离超过20。

示例输入2: [2-5-20]

  

[40,60]

     

[45,55]

     

[50,50]

     

[55,45]

     

[60,40]

如果你引导我走向正确的方向,我将非常感激。

干杯。

5 个答案:

答案 0 :(得分:10)

我希望这不是一个家庭作业问题!

    def combinations(n: Int, step: Int, distance: Int, sum: Int = 100): List[List[Int]] =
      if (n == 1) 
        List(List(sum))
      else 
        for {
          first <- (step until sum by step).toList
          rest <- combinations(n - 1, step, distance, sum - first)
          if rest forall (x => (first - x).abs <= distance)
        } yield first :: rest

答案 1 :(得分:6)

如果需要将最大距离N除以100,则组合中的最小值为

  

100/2 - N / 2

如果你需要将最多距离为N的3个值除以100,这就变得更加棘手。 3个值的平均值为100/3,但如果其中一个值远低于此平均值,则其他值只能略大于此平均值,这意味着最小值不是平均值减去最大距离两个,但可能

  

100/3 - 2N / 3

通常使用M值,这变为

  

100 / M - (M-1)N / M

可以简化为

  

(100 - (M-1)N)/ M

同样,我们可以计算出最高可能值:

  

(100 +(M-1)N)/ M

这为您提供了组合的第一个值的范围。

要确定第二个值的范围,您必须考虑以下约束:

  • 与第一个值的距离(不应高于您的最大距离)
  • 我们还能达到总和(100)

第一个约束不是问题。第二个是。

假设我们将100除以3,最大距离为30,使用10的倍数 如前所述,最小值为:

  

(100 - (3-1)30)/ 3 - &gt; 13 - &gt;四舍五入到10的下一个倍数 - &gt; 20

最大值为

  

(100 +(3-1)30)/ 3 - > 53 - &gt;四舍五入到10的前一个倍数 - &gt; 50

因此,对于第一个值,我们应该迭代20,30,40和50。

假设我们选择20.这为其他2个值留下80。 我们再次分配80超过2个值,最大距离为30,这给出了:

  

最小值:(80 - (2-1)30)/ 2 - &gt; 25 - &gt;圆形 - &gt; 30

     

最大值:(80 +(2-1)30)/ 2 - > 55 - &gt;圆形 - &gt; 50

第二个限制是我们不希望与第一个值相比大于30的距离。这至少为-10,最大为50。

现在取两个域之间的交集 - &gt; 30到50,第二个值迭代超过30,40,50。

然后重复此操作以获得下一个值。

修改 我在伪代码中添加了算法以使其更清晰:

calculateRange (vector, remainingsum, nofremainingvalues, multiple, maxdistance)
{
if (remaingsum==0)
   {
   // at this moment the nofremainingvalues should be zero as well
   // found a solution
   print vector
   return;
   }

minvalueaccordingdistribution = (remainingsum-(nofremainingvalues-1)*maxdistance)/nofremaingvalues;
maxvalueaccordingdistribution = (remainingsum+(nofremainingvalues-1)*maxdistance)/nofremaingvalues;

minvalueaccordingdistance = max(values in vector) - maxdistance;
maxvalueaccordingdistance = min(values in vector) + maxdistance;

minvalue = min (minvalueaccordingdistribution, minvalueaccordingdistance);
maxvalue = max (minvalueaccordingdistribution, minvalueaccordingdistance);

for (value=minvalue;value<=maxvalue;value+=multiple)
   {
   calculaterange (vector + value, remainingsum - value, nofremainingvalues-1, multiple, maxdistance);
   }
}

main()
{
calculaterange (emptyvector, 100, 2, 20);
}

答案 2 :(得分:2)

为什么不能在没有优化的情况下使用蛮力方法?例如,说 N - 组合数 M - 倍数 D - 最大可能距离

因此组合中的可能值可以是M,2M,3M等。你需要生成这个集合然后从set中的第一个元素开始,并尝试从同一个集合中选择值来找出接下来的两个元素(假设它们应该比第一个/第二个值小D)。 所以i / p为3-10-30会

  1. 创建一组10,20,30,40,50,60,70,80,90作为可能的值
  2. 从10开始,第二个值的选择必须是20,30,40,50(D <30)
  3. 现在从20,30,40,50的集合中选择第二个值并尝试获取下一个值,依此类推
  4. 如果使用递归,那么解决方案将变得更加简单。

    1. 您必须从a中找到N个值 MIN&amp;中的可能值列表 MAX指数。
    2. 所以先尝试一下 MIN指数(到MAX指数)。说我们 在X指数中选择了价值。
    3. 对于每个第一个值,请尝试查找 输出MIN =列表中的N-1值     X + 1和MAX。
    4. 当M = 1且N足够大时,会发生最差的性能。

答案 3 :(得分:1)

所有之间的距离是加性因子,还是 之间的距离?例如,对于3-10-20,[20-40-60]是一个有效的答案吗?我会假设后者,但下面的解决方案可以非常简单地修改以适用于前者。

无论如何,要走的路是从你可以管理的最极端的答案(一种)开始,然后一直走到最极端的另一端。

让我们尝试将数字尽可能低,除了最后一个,尽可能高(假设其他数字很低)。将公约数设为d并将100除以它,因此我们有S = 100/d。这很好地量化了我们的问题。现在我们的约束条件是间距最多为s,除非我们将其转换为多个量化步骤n = s/d。现在假设我们有M个样本,i1...iM并编写约束:

i1 + i2 + i3 + ... + iM = S
0 <= i1 <= n
0 <= i2 <= n
. . .
0 <= iM <= n
i1 <= i2
i2 <= i3
. . .
i(M-1) <= iM

我们可以解决第一个方程式,以获得iM给出其他方程式。

现在,如果我们尽可能地使一切变得相似:

i1 = i2 = ... = iM = I
M*I = S
I = S/M

非常好 - 我们有了起点! (如果I是一个分数,请将前几个I和其余I+1组合起来。)现在我们尝试依次遍历每个变量:

for (i1 = I-1 by -1 until criteria fails)
  sum needs to add to S-i1
  i2 >= i1
  i2 <= i1 +n
  solve the same problem for M-1 numbers adding to S-i1
  (while obeying the above constraint on i2)

好吧,看看这里 - 我们有一个递归算法!我们只是走过去阅读答案。

当然,我们可以走i1而不是走。如果您需要打印答案,也可以这样做。如果您只需要计算它们,请注意计数是对称的,所以只需将倒计时得到的答案加倍。 (如果不是所有值都开始相同,你也会有一个修正因子 - 如果有些值是I而有些是I+1,你需要考虑到这一点,我不会在这里做。)


编辑:如果范围是每个值必须适合的范围,而不是所有

0 <= i1 <= n

条件,你有

max(i1,i2,...,iM) - min(i1,i2,...,iM) <= n

但是这给出了相同的递归条件,除了我们传递了我们已经选择投入混合的那些项的最大值和最小值,而不是在i2上添加约束(或者任何其他变量的转过来了。)

答案 4 :(得分:0)

输入: (20年2月10日)

  1. 将数字除以参数1
  2. (50,50)

    2检查差异规则是否允许此组合。如果它损坏了规则,那么STOP,如果它允许,那么将它和它的组合添加到结果列表中

    例如:abs(50-50)&lt; 20,所以没关系

    3通过参数2增加第一个值,通过参数2减小第二个值

    1. Go 2. point