我正在尝试使用带有memoization的递归来执行此操作,我已经确定了以下基本情况。
I)当n == k时,只有一个组有所有球。
II)当k> n时,没有任何组可以拥有至少k个球,因此为零。
我无法从这里前进。如何做到这一点?
作为n = 6时的例子,k = 2 (2,2,2) (4,2) (3,3) (6)
即可形成4种不同的分组。
答案 0 :(得分:3)
这可以用下面描述的二维递归公式表示:
T(0, k) = 1
T(n, k) = 0 n < k, n != 0
T(n, k) = T(n-k, k) + T(n, k + 1)
^ ^
There is a box with k balls, No box with k balls, advance to next k
put them
在上文中,T(n,k)
是n
个球的分布数,因此每个框至少得到k
。
诀窍是将k
视为尽可能少的球数,并将问题分成两个场景:是否有一个精确k
球的盒子(如果有的话,放置它们)或者用n-k
球递归),或者没有(然后用k+1
的最小值和相同数量的球递归。)
示例,计算您的示例:T(6,2)
(6个球,每盒至少2个):
T(6,2) = T(4,2) + T(6,3)
T(4,2) = T(2,2) + T(4,3) = T(0,2) + T(2,3) + T(1,3) + T(4,4) =
= T(0,2) + T(2,3) + T(1,3) + T(0,4) + T(4,5) =
= 1 + 0 + 0 + 1 + 0
= 2
T(6,3) = T(3,3) + T(6,4) = T(0,3) + T(3,4) + T(2,4) + T(6,5)
= T(0,3) + T(3,4) + T(2,4) + T(1,5) + T(6,6) =
= T(0,3) + T(3,4) + T(2,4) + T(1,5) + T(0,6) + T(6,7) =
= 1 + 0 + 0 + 0 + 1 + 0
= 2
T(6,2) = T(4,2) + T(6,3) = 2 + 2 = 4
使用动态编程,可以在O(n^2)
时间内计算。
答案 1 :(得分:0)
这种情况可以很简单地解决:
最大桶数b
可以按如下方式确定:
b = roundDown(n / k)
每个有效的分发版最多可以使用b
个桶。
x
存储桶的分发数对于给定数量的桶,可以非常简单地找到分配数量:
向每个桶分发k
个球。找出将剩余球(r = n - k * x
)分发到x
桶的方式的数量:
total_distributions(x) = bincoefficient(x , n - k * x)
编辑:如果订单有问题,这将是onyl工作。由于它没有问题,我们可以在这里使用一些技巧:
每个分布都可以映射到一系列数字。例如:d = {d1 , d2 , ... , dx}
。我们可以轻松生成所有这些序列,从&#34; first&#34;序列{r , 0 , ... , 0}
,然后从左向右移动1。所以下一个序列看起来像这样:{r - 1 , 1 , ... , 0}
。如果仅生成匹配d1 >= d2 >= ... >= dx
的序列,则不会生成重复项。此约束可以轻松用于优化此搜索:如果给出da
,我们只能将1从db
移动到a = b - 1
(使用da - 1 >= db + 1
),因为否则违反了数组的排序约束。移动的1s总是最可移动的。想到这一点的另一种方法是将r
视为一元数,然后简单地将该字符串拆分成组,以便每个组至少是它的后继者。
countSequences(x)
sequence[]
sequence[0] = r
sequenceCount = 1
while true
int i = findRightmostMoveable(sequence)
if i == -1
return sequenceCount
sequence[i] -= 1
sequence[i + 1] -= 1
sequenceCount
findRightmostMoveable(sequence)
for i in [length(sequence) - 1 , 0)
if sequence[i - 1] > sequence[i] + 1
return i - 1
return -1
如果我们查看序列的结构转换(更准确地说是序列的两个元素之间的差异),实际上findRightmostMoveable
可以稍微优化一下。但说实话,我到目前为止还懒得进一步优化。
range(1 , roundDown(n / k)).map(b -> countSequences(b)).sum()