我遇到了一个棘手的情况,我需要根据不同的因素来计算形成100的组合数。
那些是
示例输入1:(2-10-20)
这意味着
输出
[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]
如果你引导我走向正确的方向,我将非常感激。
干杯。
答案 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除以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会
如果使用递归,那么解决方案将变得更加简单。
当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日)
(50,50)
2检查差异规则是否允许此组合。如果它损坏了规则,那么STOP,如果它允许,那么将它和它的组合添加到结果列表中
例如:abs(50-50)&lt; 20,所以没关系
3通过参数2增加第一个值,通过参数2减小第二个值